Я не должен создавать классы с целью возврата нескольких значений
классы никогда не должны использоваться как структуры C ++, только для группировки элементов.
методы не должны возвращатьне примитивные объекты, они должны получать объект извне и только изменять его
Для любого из приведенных выше утверждений это определенно не так.Объекты данных полезны, и на самом деле, это хорошая практика, чтобы отделить чистые данные от классов, содержащих тяжелую логику.
В Java самая близкая вещь, которую мы имеем к структуре, это POJO (обычный старый объект Java), обычноизвестный как классы данных в других языках.Эти классы являются просто группировкой данных.Практическое правило для POJO заключается в том, что он должен содержать только примитивы, простые типы (строки, штучные примитивы и т. Д.), Простые контейнеры (map, array, list и т. Д.) Или другие классы POJO.Основные классы, которые можно легко сериализовать.
Обычно требуется объединить два, три или n
объекты вместе.Иногда данные достаточно значительны, чтобы гарантировать совершенно новый класс, а в других нет.В этих случаях программисты часто используют Pair
или Tuple
классы.Вот быстрый пример универсального кортежа из двух элементов.
public class Tuple2<T,U>{
private final T first;
private final U second;
public Tuple2(T first, U second) {
this.first = first;
this.second = second;
}
public T getFirst() { return first; }
public U getSecond() { return second; }
}
Класс, который использует кортеж как часть сигнатуры метода, может выглядеть следующим образом:
public interface Container<T> {
...
public Tuple2<Boolean, Integer> search(T key);
}
Недостаток созданияПодобные классы данных заключаются в том, что для качества жизни мы должны реализовать такие вещи, как toString
, hashCode
, equals
геттеры, сеттеры, конструкторы и т. д. Для каждого кортежа разного размера вы должны создать новый класс (Tuple2
, Tuple3
, Tuple4
и т. Д.).Создание всех этих методов вносит незначительные ошибки в наши приложения.По этим причинам разработчики часто избегают создания классов данных.
Такие библиотеки, как Lombok, могут быть очень полезны для преодоления этих проблем.Наше определение Tuple2
со всеми перечисленными выше методами можно записать так:
@Data
public class Tuple2<T,U>{
private final T first;
private final U second;
}
Это также чрезвычайно упрощает создание пользовательских классов ответов.Использование пользовательских классов позволяет избежать автобокс с универсальными шаблонами и значительно повысить читаемость.Например:
@Data
public class SearchResult {
private final boolean found;
private final int index;
}
...
public interface Container<T> {
...
public SearchResult search(T key);
}
методы должны получать объект извне и изменять его только
Это плохой совет.Намного приятнее проектировать данные на основе неизменности.Начиная с Effective Java 2nd Edition, стр. 75
Неизменяемые объекты просты .Неизменяемый объект может находиться ровно в одном состоянии, в состоянии, в котором он был создан.Если вы убедитесь, что все конструкторы устанавливают инварианты классов, то гарантируется, что эти инварианты будут оставаться верными всегда, без каких-либо дополнительных усилий с вашей стороны или со стороны программиста, который использует класс.Изменяемые объекты, с другой стороны, могут иметь произвольно сложные пространства состояний.Если документация не дает точного описания переходов состояний, выполняемых методами-мутаторами, может быть трудно или невозможно надежно использовать изменяемый класс.
Неизменяемые объекты по своей природе поточно-ориентированы ;они не требуют синхронизации.Они не могут быть повреждены несколькими потоками, обращающимися к ним одновременно.Это, безусловно, самый простой подход к обеспечению безопасности потоков.Фактически, ни один поток не может наблюдать какое-либо влияние другого потока на неизменный объект.Следовательно, неизменяемые объекты могут свободно использоваться совместно .