Рубрики
Без рубрики

Java конструкторы против статических методов завода

Узнайте о статических методах фабрики в Java и о том, почему они иногда предпочтительнее конструкторов для мгновенного и инициализации объектов.

Автор оригинала: baeldung.

1. Обзор

Java-конструкторы — это механизм по умолчанию для получения полностью инициализированных экземпляров классов. В конце концов, они обеспечивают всю инфраструктуру, необходимую для введения зависимостей, либо вручную, либо автоматически.

Несмотря на это, в некоторых конкретных случаях использования, предпочтительнее прибегнуть к статическим методам завода для достижения того же результата.

В этом учебнике мы будем подчеркивать плюсы и минусы использования статических методов фабрики против простых старых Java-конструкторов .

2. Преимущества статических методов фабрики над конструкторами

На объектно-ориентированном языке, как Java, что может быть не так со конструкторами? В целом, ничего. Несмотря на это, знаменитый Эффективный Java-элемент Джошуа Блока 1 четко говорится:

“Рассмотрите статические заводские методы вместо конструкторов”

Хотя это не серебряная пуля, вот наиболее веские причины, которые поддерживают этот подход:

  1. Конструкторы не имеют значимых имен , поэтому они всегда ограничиваются стандартной конвенцией именования, навязанной языком. Статические заводские методы могут иметь значимые , следовательно, явно передачи того, что они делают
  2. Статические методы фабрики могут вернуть тот же тип, который реализует метод (ы), подтип, а также примитивы , поэтому они предлагают более гибкий диапазон возвращающихся типов
  3. Статические методы фабрики могут инкапсулировать всю логику, необходимую для предварительного построения полностью инициализированных экземпляров , так что они могут быть использованы для перемещения этой дополнительной логики из конструкторов. Это не позволяет конструкторам выполнение дальнейших задач, другие, чем просто инициализация полей
  4. Статические методы фабрики можно контролировать- экземплярами , с Синглтон шаблон является наиболее вопиющим примером этой функции

3. Методы статических фабрик в JDK

Есть много примеров статических методов завода в JDK, которые демонстрируют многие из преимуществ, изложенных выше. Давайте рассмотрим некоторые из них.

3.1. Класс струн

Из-за известного Струнный интернирование , это очень маловероятно, мы будем использовать Струнные конструктор класса для создания нового Струнные объект. Несмотря на это, это совершенно законно:

String value = new String("Baeldung");

В этом случае конструктор создаст новую Струнные объект, который является ожидаемым поведением.

Кроме того, если мы хотим создать новую Струнные объект, использующий статический метод , мы можем использовать некоторые из следующих реализаций valueOf() метод:

String value1 = String.valueOf(1);
String value2 = String.valueOf(1.0L);
String value3 = String.valueOf(true);
String value4 = String.valueOf('a');

Есть несколько перегруженных реализаций valueOf() . Каждый из них вернет новый Струнные объект, в зависимости от типа аргумента, передаваемого методу (например, int , long , boolean , char, и так далее).

Название довольно ясно выражает то, что метод делает. Он также придерживается устоявшегося стандарта в экосистеме Java для именования статических методов завода.

3.2. Дополнительный класс

Другим аккуратным примером статических заводских методов в JDK является Необязательный класс. Этот класс реализует несколько заводских методов с довольно значимыми названиями , в том числе пустой () , () , и изNullable() :

Optional value1 = Optional.empty();
Optional value2 = Optional.of("Baeldung");
Optional value3 = Optional.ofNullable(null);

3.3. Класс коллекций

Вполне возможно, наиболее репрезентативным примером статических заводских методов в JDK является Коллекции класса. Это не мгновенный класс, который реализует только статические методы.

Многие из них являются заводскими методами, которые также возвращают коллекции, после применения к поставляемой коллекции какого-либо алгоритма.

Вот несколько типичных примеров заводских методов класса:

Collection syncedCollection = Collections.synchronizedCollection(originalCollection);
Set syncedSet = Collections.synchronizedSet(new HashSet());
List unmodifiableList = Collections.unmodifiableList(originalList);
Map unmodifiableMap = Collections.unmodifiableMap(originalMap);

Количество статических заводских методов в JDK действительно обширно, поэтому мы будем держать список примеров коротким для краткости ради.

Тем не менее, приведенные выше примеры должны дать нам четкое представление о том, как вездесущие статические методы завода находятся в Java.

4. Пользовательские статические методы фабрики

Конечно, мы можем внедрить наши собственные статические методы завода. Но когда это действительно стоит сделать, вместо того, чтобы создавать классные экземпляры с помощью простых конструкторов?

Давайте посмотрим простой пример.

Давайте рассмотрим эту наивную Пользователь класс:

public class User {
    
    private final String name;
    private final String email;
    private final String country;
    
    public User(String name, String email, String country) {
        this.name = name;
        this.email = email;
        this.country = country;
    }
    
    // standard getters / toString
}

В этом случае нет видимых предупреждений, указывающих на то, что статический метод фабрики может быть лучше стандартного конструктора.

Что, если мы хотим, чтобы все Пользователь экземпляры получают значение по умолчанию для страна поле?

Если мы инициализируем поле со значением по умолчанию, нам также придется рефакторировать конструктора, что делает конструкцию более жесткой.

Вместо этого мы можем использовать статический метод фабрики:

public static User createWithDefaultCountry(String name, String email) {
    return new User(name, email, "Argentina");
}

Вот как мы могли бы получить Пользователь экземпляр с значением по умолчанию, присвоенным страна поле:

User user = User.createWithDefaultCountry("John", "[email protected]");

5. Перемещение логики из конструкторов

Наша Пользователь класс может быстро сгнить в недостатки дизайна, если мы решим реализовать функции, которые потребуют добавления дополнительной логики конструктора (тревожные колокола должны звучать покинуть к этому времени).

Предположим, что мы хотим предоставить классу возможность регистрации времени, в которое каждый Пользователь объект создается.

Если мы просто вложу эту логику в конструктора, мы Принцип единой ответственности . Мы бы в конечном итоге с монолитным конструктором, который делает гораздо больше, чем инициализировать поля.

Мы можем сохранить наш дизайн чистым с помощью статического метода завода:

public class User {
    
    private static final Logger LOGGER = Logger.getLogger(User.class.getName());
    private final String name;
    private final String email;
    private final String country;
    
    // standard constructors / getters
    
    public static User createWithLoggedInstantiationTime(
      String name, String email, String country) {
        LOGGER.log(Level.INFO, "Creating User instance at : {0}", LocalTime.now());
        return new User(name, email, country);
    }
}

Вот как мы бы создать нашу улучшенную Пользователь пример:

User user 
  = User.createWithLoggedInstantiationTime("John", "[email protected]", "Argentina");

6. Инстанция-контролируемая мгновенное

Как показано выше, мы можем инкапсулировать куски логики в статические методы завода, прежде чем вернуть полностью инициализированные Пользователь Объектов. И мы можем сделать это, не загрязняя конструктора с ответственностью выполнения нескольких, не связанных между собой задач.

Например, Предположим, мы хотим сделать нашу Пользователь класс Синглтон. Мы можем достичь этого путем внедрения управляемого экземпляром статического метода фабрики:

public class User {
    
    private static volatile User instance = null;
    
    // other fields / standard constructors / getters
    
    public static User getSingletonInstance(String name, String email, String country) {
        if (instance == null) {
            synchronized (User.class) {
                if (instance == null) {
                    instance = new User(name, email, country);
                }
            }
        }
        return instance;
    }
}

Осуществление getSingletonInstance() метод поток-безопасный, с небольшим штрафом производительности, из-за синхронизированного блока .

В этом случае мы использовали ленивую инициализацию, чтобы продемонстрировать реализацию управляемого экземпляром статического метода фабрики.

Стоит отметить, однако, что лучший способ реализовать Singleton с Java- enum типа, так как это как сериализация-безопасный и поток-безопасный . Для получения подробной информации о том, как реализовать Singletons с использованием различных подходов, пожалуйста, проверьте эта статья .

Как и ожидалось, получить Пользователь объект с этим методом очень похож на предыдущие примеры:

User user = User.getSingletonInstance("John", "[email protected]", "Argentina");

7. Заключение

В этой статье мы изучили несколько случаев использования, когда статические методы фабрики могут быть лучшей альтернативой использованию простых Java-конструкторов.

Более того, эта модель рефакторинга настолько прочно укоренилась в типичном рабочем процессе, что большинство ИДВ сбудут делать это за нас.

Конечно, Apache NetBeans , IntelliJ IDEA , и Затмение будет выполнять рефакторинг несколько по-разному, поэтому, пожалуйста, убедитесь, что сначала проверить вашу документацию IDE.

Как и во многих других шаблонах рефакторинга, мы должны использовать статические методы завода с должной осторожностью, и только тогда, когда это стоит компромисс между производством более гибкой и чистой конструкции и стоимость того, чтобы реализовать дополнительные методы.

Как обычно, все образцы кода, показанные в этой статье, доступны более на GitHub .