#design-patterns #factory #factory-pattern #factory-method #static-factory
#шаблоны проектирования #фабрика #фабричный шаблон #фабричный метод #статический-завод
Вопрос:
Речь идет о фабричном шаблоне. Я немного смущен.
Я видел реализации, в которых createInstance()
метод является статическим, и некоторые реализации, которые не являются статическими.
Некоторые говорят, что это зависит от «стиля» или «вкуса», а некоторые говорят, что это не так. Википедия говорит, что он должен быть нестатическим, и http://www.dofactory.com/Patterns/PatternFactory.aspx также говорится, что он должен быть нестатичным, согласно Gang of Four.
Мой вопрос: зависит ли это от стиля и вкуса или нарушает фабричный шаблон, если он реализован статическим способом? Что правильно?
Ответ №1:
Я очень не решаюсь классифицировать «экземпляр против статического» как дело вкуса. Это подразумевает, что это эстетично, как любимый цвет или, что более уместно, camelCase против PascalCase.
Сравнение экземпляра со статическим — это скорее вопрос компромиссов. Используя элементы экземпляра любого типа, вы получаете все преимущества полиморфизма, поскольку вы можете реализовывать интерфейсы и наследовать от других классов, когда у вас есть экземпляры и члены экземпляра. Со статикой вы не получаете этих преимуществ. Как правило, статический по сравнению с экземпляром — это компромисс между начальной простотой и последующей простотой. Статика проста, потому что она доступна во всем мире, и вам не нужно думать о таких вещах, как «когда это должно быть создано и кем?» Вам не нужно передавать их с помощью средств доступа / мутаторов или конструкторов, и ваш API выглядит чище. Это упрощает предварительные рассуждения. Но это усложняет обслуживание и будущие реализации.
Если у вас есть статический метод — скажем, фабричный метод в вашем случае — и вы позже хотите, чтобы он вел себя по-другому в определенных ситуациях, вы как бы поливаете из шланга. Вы должны создать второй метод и скопировать и вставить функциональность за вычетом всего, что вы хотите изменить, а затем попросить клиентов разобраться с этим. Или, что еще хуже, вы предоставляете глобальную переменную, и клиенты устанавливают ее до и после использования вашего метода, при этом глобальный указывает методу, как себя вести.
Если бы вы прошли путь экземпляра заранее, это было бы легко. Вы просто унаследуете и переопределите свой первоначальный фабричный метод и предоставите производные классы, где вам нужна новая функциональность. Вы не создаете дополнительной нагрузки на клиентский код и почти не вносите изменений в существующие классы (принцип open / closed).
Мой совет состоял бы в том, чтобы в будущем оказать вам и / или другим сопровождающим услугу и использовать реализацию экземпляра. Это не вопрос того, что хочет или предпочитает Gang of Four или кто-либо еще — это вопрос вашего собственного здравомыслия перед лицом гнили кода.
Ответ №2:
Статический метод не нарушает шаблон, но он противоречит многим другим объектно-ориентированным практикам (инверсия управления внедрение зависимостей в качестве одного примера), поэтому лучше использовать экземпляры.
Редактировать:
Я только что получил какой-то значок для этого ответа, но когда я прочитал его, я не мог поверить своим глазам. Это неправильно, когда мы строго говорим о шаблоне фабричного метода GoF, и это заслуживает некоторого исправления.
У вас может быть статический CreateInstance
метод для создания экземпляра типа — в этом нет ничего плохого — люди часто называют это фабричным методом, но это не то, что называется шаблоном фабричного метода. Как только вы начнете вводить логику в этот метод для создания экземпляров разных типов в зависимости от некоторых условий, вам может понадобиться шаблон фабричного метода, описанный GoF.
Суть шаблона фабричного метода GoF заключается в замене условной логики внутри CreateInstance
наследованием и полиморфизмом, и поэтому он не может быть статичным. Фабричный метод — это метод экземпляра, более того, он виртуальный. Ваш базовый тип обычно имеет абстрактную CreateInstance
и условную логику, заменяемую деревом наследования, где каждый подтип переопределяет CreateInstance
и создает только определенный продукт для этого подтипа.
Комментарии:
1. Не могли бы вы использовать статическую инъекцию, например
static void setFactory(Factory fact)
?2. Хорошо, спасибо. Мне не нужно ничего менять. Ваш аргумент соответствует моему представлению об ооп. Спасибо, что подтвердили это.
3. @corsiKlauseHoHoHo — Это означает, что вы должны помнить об использовании setFactory() каждый раз, когда вам нужно использовать factory. В отличие от класса экземпляра, вам необходимо использовать конструктор, что избавляет вас от необходимости запоминать требуемые методы.
4. @Yorro нет, вам нужно будет установить завод только один раз при запуске системы или по требованию из-за изменения конфигурации по запросу пользователя. Вы все равно можете вводить его динамически на основе параметров конфигурации. Если бы я каждый раз вызывал setFactory(), я бы предположил, что вместо фабрик я бы использовал конструкторы, а запуск их через статический метод включал бы обман, такой как threadlocal внутри… В этом случае я бы предпочел иметь фабрику разработчиков…
Ответ №3:
Если abstract factory
это, то уровень экземпляра нормальный. И функциональность уровня экземпляра, как правило, легче имитировать и модульно тестировать, чем static
уровень