Почему фабричный шаблон работает так, как работает? - PullRequest
3 голосов
/ 28 января 2011

Я никогда по-настоящему не смотрел на шаблон «Фабрика», и сегодня решил не торопиться и создать быстрый образец на основе этой статьи (http://msdn.microsoft.com/en-us/library/ee817667.aspx),, чтобы наконец разобраться с ним.

Исходный код прекрасно работает в трех отдельных сборках, называемых Product, Factory и Client.

Основная выгода (как я понимаю) для шаблона Factory состоит в том, чтобы абстрагировать экземпляр класса «product» отКласс «Клиент». Таким образом, в представленном примере экземпляр продукта никогда не изменяется независимо от каких-либо изменений, внесенных в класс продукта, вам все равно нужно внести изменения в класс клиента, чтобы передать новые значения Zin, необходимые для создания обновленного продукта. Эти данныев конце концов, откуда-то должно прийти?

Другой пример, который я прочитал, гласил, что как только класс будет реализован, и множество других классов будут использовать его напрямую, изменения, внесенные в класс "product", потребуют измененийсделано для каждого экземпляра этого класса, скажем, для экзаменаЕсли в конструкторе требовалась новая переменная.

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

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

Учитывая, чтоэто установленная модель, я явно что-то упускаю.Отсюда и этот пост: Пожалуйста, объясните мне, что мне не хватает.

Спасибо

Ответы [ 4 ]

8 голосов
/ 28 января 2011

Фабрика используется, когда у вас может быть много разных реализаций одного и того же интерфейса, и только во время выполнения определяется, какая именно клиенту нужна на самом деле. Однако клиенту не нужно знать, какую реализацию он на самом деле использует. Вот тут-то и вступает Factory: она инкапсулирует детали создания конкретного объекта и возвращает его как общую реализацию требуемого интерфейса.

На самом деле с именем Фабрики связаны два разных шаблона: Абстрактная Фабрика и Фабричный Метод . Последний используется для создания экземпляров одного продукта, а первый - для создания целого семейства связанных продуктов.

Типичным примером Abstract Factory является создание семейства виджетов в среде GUI. Клиентам платформы может потребоваться только знать, что они имеют дело с окном, или строкой состояния, или кнопкой; однако их не нужно привязывать к факту, является ли данный виджет на самом деле виджетом для Windows или MacOS. Это позволяет создавать клиентов, которые могут работать на любой из этих платформ; и теоретически, когда фреймворк переносится на новую платформу, скажем, Linux, все, что нужно, это реализовать новую фабрику, которая производит все специфичные для Linux виджеты, и подключить ее через конфигурацию. И вот, клиенты работают в Linux, не замечая никакой разницы, возможно, даже без необходимости перекомпиляции клиентского кода (по крайней мере, теоретически, а в некоторых языках - я знаю, что реальность в отношении многоплатформенных графических интерфейсов отличается, но это только пример: -)

Сравните это с попыткой реализовать то же самое без фабрик: у вас будет много мест в клиентском коде, где вам нужно будет решить, какой виджет для конкретной платформы вам нужно создать. И всякий раз, когда вы хотите представить новое семейство виджетов, вам нужно будет изменить каждое из этих мест в вашем коде, чтобы добавить новую ветвь для множества идентичных блоков switch или if/else. Более того, поскольку вы будете открыто иметь дело с объектами виджетов, зависящими от платформы, есть вероятность, что некоторые специфичные для платформы особенности виджетов и детали реализации попадут в клиентский код, что сделает его еще более трудным для переноса на другие платформы.

Реализация продукта никогда не изменяется независимо от каких-либо изменений, внесенных в класс продукта, вам все равно нужно внести изменения в класс клиента, чтобы передать новые значения Zin, необходимые для создания вашего обновленного продукта. Эти данные ведь должны откуда-то приходить?

Действительно. Если общий процесс создания экземпляра изменится, интерфейс Factory может измениться соответственно. Это не точка Фабрики. Хотя вы можете передавать данные на завод во время его создания, которые затем можно использовать в фоновом режиме при создании нового продукта.

3 голосов
/ 28 января 2011

Использование фабрики - это форма Инверсия зависимости , способ отделения клиента от реализации.

Например, рассмотрим следующее:

class Client {
    private DatabaseReader reader = new DatabaseReader();
    public void read() {
        reader.read();
    }
}

Где DatabaseReader - это конкретный класс. Давайте попробуем разорвать эту связь, определив интерфейс:

class Client {
    private Reader reader = new DatabaseReader();
    ...
}

Почти там:

class Client {
    private Reader reader = ReaderFactory.getInstance.getReader();
    ...
}

Теперь клиенту все равно, получит ли он DatabaseReader, MemoryReader и т. Д. ReaderFactory несет ответственность за предоставление подходящего Reader.

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

class Client {
    @Inject 
    private Reader reader;
    ...
}

Где вы можете иметь различную проводку, объявленную для тестовых / рабочих сред.

1 голос
/ 28 января 2011

В C ++ нет виртуальных конструкторов.Это все еще не так просто в таких языках, как Java.Это означает, что нужно всегда точно знать, на каком объекте создается объект, где он создается.Это серьезная проблема для плагинов, поскольку она не позволяет абстрагироваться от кода создания объекта.

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

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

1 голос
/ 28 января 2011

Вот выдержка из википедии по фабричному шаблону:

Для создания объекта часто требуются сложные процессы, которые не следует включать в составной объект.Создание объекта может привести к значительному дублированию кода, может потребовать информацию, не доступную для объекта-составителя, может не обеспечить достаточный уровень абстракции или иным образом не может быть частью проблем объекта-составителя.1006 * Таким образом, существует несколько уровней преимуществ, которые могут присутствовать в каждом конкретном случае, или только некоторые.

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

Вот еще одна грубая идея, чтобы объяснить это: для простого объекта вы просто используете new MyClass(some_arg).Если создание экземпляра значительно сложнее, вам потребуется несколько строк кода и, возможно, дополнительные вспомогательные методы.Фабрика сводит это обратно к простой Factory.createMyClass(some_arg).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...