При моделировании классов, какой предпочтительный способ инициализации:
- Конструкторы, или
- Фабрика Методы
И каковы были бы соображения для использования любого из них?
В определенных ситуациях я предпочитаю иметь фабричный метод, который возвращает ноль, если объект не может быть построен. Это делает код аккуратным. Я могу просто проверить, не является ли возвращаемое значение нулевым, прежде чем предпринимать альтернативное действие, в отличие от выдачи исключения из конструктора. (Лично я не люблю исключения)
Скажем, у меня есть конструктор класса, который ожидает значение id. Конструктор использует это значение для заполнения класса из базы данных. В случае, когда запись с указанным идентификатором не существует, конструктор создает исключение RecordNotFoundException. В этом случае мне придется заключить конструкцию всех таких классов в блок try..catch.
В отличие от этого у меня может быть статический метод фабрики для тех классов, который будет возвращать ноль, если запись не найдена.
Какой подход лучше в этом случае, конструктор или фабричный метод?
Спросите себя, кто они и зачем они у нас. Они оба здесь, чтобы создать экземпляр объекта.
Никакой разницы пока нет. Теперь представьте, что у нас есть различные типы школ, и мы хотим переключиться с использования ElementarySchool на HighSchool (который получен из ElementarySchool или реализует тот же интерфейс ISchool, что и ElementarySchool). Изменение кода будет:
В случае интерфейса у нас будет:
Теперь, если у вас есть этот код в нескольких местах, вы можете увидеть, что использование фабричного метода может быть довольно дешевым, потому что, как только вы измените фабричный метод, все готово (если мы используем второй пример с интерфейсами).
И это главное отличие и преимущество. Когда вы начинаете работать со сложной иерархией классов и хотите динамически создавать экземпляр класса из такой иерархии, вы получаете следующий код. Затем фабричные методы могут принимать параметр, который сообщает методу, какой конкретный экземпляр нужно создать. Допустим, у вас есть класс MyStudent, и вам нужно создать экземпляр соответствующего объекта ISchool, чтобы ваш ученик был членом этой школы.
Теперь у вас есть одно место в вашем приложении, которое содержит бизнес-логику, которая определяет, какой объект ISchool создавать для различных объектов IStudent.
Итак, для простых классов (объектов-значений и т. Д.) Конструктор - это нормально (вы не хотите чрезмерно улучшать работу приложения), но для сложных иерархий классов предпочтительным способом является фабричный метод.
Таким образом, вы следуете первому принципу дизайна из банды из четырех книг «Программа для интерфейса, а не для реализации».
источник
IFood sandwich = new Sandwich(Cheese chz, Meat meat);
иIFood soup = new Soup(Broth broth, Vegetable veg);
как фабрика и / или строитель могут помочь здесь?Вам нужно прочитать (если у вас есть доступ) Effective Java 2 Item 1: Рассмотрите статические фабричные методы вместо конструкторов .
Преимущества статических фабричных методов:
Недостатки статических заводских методов:
источник
( factory methods are better than Constructors. ( Item-1 ) ) Effective java
По умолчанию конструкторы должны быть предпочтительнее, потому что их проще понимать и писать. Однако, если вам конкретно необходимо отделить конструктивные особенности объекта от его семантического значения, как это понимается в клиентском коде, вам лучше использовать фабрики.
Разница между конструкторами и фабриками аналогична, скажем, переменной и указателю на переменную. Есть другой уровень косвенности, который является недостатком; но есть и другой уровень гибкости, что является преимуществом. Так что, делая выбор, вы бы посоветовали провести анализ затрат и выгод.
источник
Используйте фабрику только тогда, когда вам нужен дополнительный контроль при создании объектов, способом, который нельзя сделать с помощью конструкторов.
Например, на фабриках есть возможность кеширования.
Другой способ использовать фабрики - это сценарий, в котором вы не знаете тип, который хотите построить. Часто вы видите этот тип использования в сценариях фабрики плагинов, где каждый плагин должен происходить из базового класса или реализовывать некоторый интерфейс. Фабрика создает экземпляры классов, которые являются производными от базового класса или реализуют интерфейс.
источник
Цитата из "Эффективной Java", 2-е изд., Пункт 1: Рассмотрим статические фабричные методы вместо конструкторов, с. 5:
«Обратите внимание, что метод статической фабрики не совпадает с шаблоном фабричного метода из шаблонов проектирования [Gamma95, стр. 107]. Метод статической фабрики, описанный в этом пункте, не имеет прямого эквивалента в шаблонах проектирования».
источник
В дополнение к «эффективной Java» (как упоминалось в другом ответе), другая классическая книга также предлагает:
Например. не пиши
но вместо этого напиши
Книга идет до того, что предлагает сделать
Complex(float)
конструктор частным, чтобы заставить пользователя вызывать статический метод фабрики.источник
from…
,to…
,parse…
,with…
, и так далее. Имейте в виду, что классы java.time созданы для того, чтобы быть неизменными, но некоторые из этих соглашений об именах могут быть полезны и для изменяемых классов.Конкретный пример из приложения CAD / CAM.
Путь резки будет сделан с помощью конструктора. Это серия линий и дуг, определяющих путь к разрезу. Хотя серии линий и дуг могут быть разными и иметь разные координаты, это легко обрабатывается путем передачи списка в конструктор.
Форма будет изготовлена с использованием фабрики. Потому что, хотя существует класс фигур, каждая фигура будет настроена по-разному, в зависимости от типа фигуры. Мы не знаем, какую форму мы будем инициализировать, пока пользователь не сделает выбор.
источник
Этот процесс определенно должен быть вне конструктора.
Конструктор не должен обращаться к базе данных.
Задача и причина для конструктора состоит в том, чтобы инициализировать элементы данных и установить инвариант класса, используя значения, переданные в конструктор.
Для всего остального лучше использовать статический метод фабрики или, в более сложных случаях, отдельный класс фабрики или конструктора .
Некоторые руководящие указания конструктора от Microsoft :
И
источник
Иногда вам нужно проверить / вычислить некоторые значения / условия при создании объекта. И если он может бросить исключение - конструктор очень плохой путь. Так что вам нужно сделать что-то вроде этого:
Где все дополнительные вычисления в init (). Но только вы как разработчик действительно знаете об этом init (). И конечно, через несколько месяцев вы просто забудете об этом. Но если у вас есть фабрика - просто сделайте все, что вам нужно, в одном методе с сокрытием этого init () от прямого вызова - так что никаких проблем. При таком подходе нет проблем с падением на создание и утечкой памяти.
Кто-то рассказал вам о кешировании. Это хорошо. Но вы также должны помнить о шаблоне Flyweight, который удобно использовать в Factory.
источник