CodeLAB
на главную карта сайта обратная связь
каталог | задачи | паттерны | исходники | стат | форумы | ссылки
 гость
искать в
Главная >> Каталог задач >> Паттерны >> Порождающие >> Фабричный метод (Factory Method)

<< назад
распечатать обсудить >>


Фабричный метод (Factory Method)
реализации: java, количество: 10

Aвтор: this
Дата: 05.06.2007
Просмотров: 100528
Рейтинг: 6/0,6(1)
+
реализации(исходники) +добавить

Имя

«Паттерн
Factory Method» codelab.ru оригинал codelab.ru источник
Фабричный метод – паттерн, порождающий подклассы. источник оригинал codelab.ru codelab.ru

Условия, Задача, Назначение

Задает интерфейс для создания объекта, и оставляет подклассам выбор того, какие в действительности классы инстанцировать (среди «Си»-шников был известен также под названием виртуальный конструктор).

Мотивация

Рассмотрим истоки выделения решения в этот отдельный паттерн. Подумаем о каркасах систем, составляющих их архитектуру.  Каркасы пользуются абстрактными классами для определения и поддержания отношений между объектами. Кроме того, каркас часто отвечает за создание самих объектов. codelab.ru codelab.ru оригинал источник
Рассмотрим каркас для приложений, способных представлять пользователю сразу несколько документов. Две основных абстракции в таком каркасе – это классы Application и Document. Оба класса абстрактные, поэтому клиенты должны порождать от них подклассы для создания специфичных для приложения реализаций. Например, чтобы создать приложение для рисования, мы определим классы DrawingApplication и DrawingDocument. Класс Application отвечает за управление документами и создает их по мере необходимости, допустим, когда пользователь выбирает из меню пункт Open (открыть) или New (создать). codelab.ru codelab.ru источник оригинал
Поскольку решение о том, какой подкласс класса Document инстанцировать, зависит от приложения, то Application не может «предсказать», что именно понадобится, в смысле, какой конкретный класс нужно будет инстанцировать. Этому участнику известно лишь, когда нужно инстанцировать новый документ, а не какой документ создать. Возникает дилемма: каркас должен инстанцировать классы, но «знает» он лишь об абстрактных классах, которые инстанцировать нельзя. оригинал codelab.ru источник codelab.ru

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

источник codelab.ru codelab.ru оригинал

Подклассы класса Application переопределяют абстрактную операцию CreateDocument таким образом, чтобы она возвращала подходящий подкласс класса Document. Как только подкласс Application инстанцирован, он может инстанцировать специфические для приложения документы, ничего не зная об их классах. Операцию CreateDocument мы называем фабричным методом, поскольку она отвечает за «изготовление» объекта. источник оригинал codelab.ru codelab.ru

  codelab.ru codelab.ru оригинал источник

Признаки применения, использования паттерна Фабричный метод (Factory Method)

Если: источник оригинал codelab.ru codelab.ru
  1. Классу заранее неизвестно, объекты каких классов ему нужно создавать, поскольку предполагается много различных вариантов функционирования. оригинал codelab.ru codelab.ru источник
  2. класс спроектирован так, чтобы объекты, которые он создает, определялись(специфицировались) только уже в подклассе. codelab.ru codelab.ru источник оригинал
  3. Класс делегирует свои обязанности одному из нескольких вспомогательных подклассов, и вы планируете локализовать знание о том, какой класс принимает эти обязанности на себя. Т.е. функциональность логически разделена между главным классом и вспомогательными, каждый из которых выполняет свою конкретную небольшую функцию. И вот здесь требуется гибкость, чтобы позволить легко заменять эти вспомогательные классы. codelab.ru источник codelab.ru оригинал

Решение

оригинал codelab.ru codelab.ru источник

codelab.ru источник codelab.ru оригинал

Участники паттерна Фабричный метод (Factory Method)

codelab.ru оригинал источник codelab.ru

  1. Product(Document) – продукт, абстрактный класс.
    Определяет структуру, интерфейс объектов, создаваемых фабричным методом. codelab.ru источник оригинал codelab.ru
  2. ConcreteProduct(MyDocument) – конкретный продукт, класс.
    Реализует интерфейс Product, т.е. представляет один из вариантов реализации всех действий, возложенных на сущность Product. источник codelab.ru оригинал codelab.ru
  3. Creator(Application) – создатель(«главный класс»), здесь он пока абстрактный.
    Объявляет фабричный метод, возвращающий объект типа Product.
    Creator может также определять реализацию по-умолчанию фабричного метода,  который возвращает объект ConcreteProduct.
    Может вызывать фабричный метод для создания объекта Product. источник codelab.ru codelab.ru оригинал
  4. ConcreteCreator(MyApplication) – продукт, абстрактный класс.
    Определяет структуру, интерфейс объектов, создаваемых фабричным метод. codelab.ru codelab.ru оригинал источник
  оригинал codelab.ru источник codelab.ru

Схема использования паттерна Фабричный метод (Factory Method)

Ответственность за то, какие реально классы будут фигурировать в приложении – создатель назначает подклассам. источник codelab.ru codelab.ru оригинал

Таким образом в каркасе приложения фигурируют только класса Product и Creator. С помощью них выполняется какой-то общий алгоритм. Дальше – в уже клиентской части приложения, использующей этот каркас, на каждом этапе отдельно решается какой конкретно подкласс ConcreteProduct и ConcreteCreator инстанцируется, после чего запускается на выполнение этот общий алгоритм определенный каркасом, который уже используя эти подклассы получает на выходе конкретный вариант результатов функционирования. оригинал codelab.ru codelab.ru источник

Вопросы, касающиеся реализации паттерна Фабричный метод (Factory Method)

Некоторые аспекты, возникающие при использовании данного паттерна: оригинал источник codelab.ru codelab.ru
  1. 2 основных разновидности паттерна.
    Во-первых, это случай, когда класс Сreator является абстрактным и не содержит реализации объявленного в нем фабричного метода. Вторая возможность: Creator – конкретный класс, в котором по умолчанию есть реализация фабричного метода.
    Редко, но встречается и абстрактный класс, имеющий реализацию по умолчанию; В первом случае для определения реализации необходимы подклассы, поскольку никакого разумного умолчания не существует. При этом обходится проблема, связанная с необходимостью инстанцировать заранее неизвестные классы.
    Во-втором случае конкретный класс Creator использует фабричный метод, главным образом ради повышения гибкости. Выполняется правило: «Создавай объекты в отдельной операции, чтобы подклассы могли подменить способ их создания». Соблюдение этого правила гарантирует, что авторы подклассов смогут при необходимости изменить класс объектов, инстанцируемых их родителем. codelab.ru источник оригинал codelab.ru
  2. Параметризованные фабричные методы.
    Это еще один вариант паттерна, который позволяет фабричному методу создавать разные виды продуктов.
    Фабричному методу передается параметр, который идентифицирует вид создаваемого объекта. Все объекты, получающиеся с помощью фабричного метода, разделяют общий интерфейс Product. В примере с документами класс Application может поддерживать разные виды документов. Вы передаете методу CreateDocument лишний параметр, который и определяет, документ какого вида нужно создать.
    Параметризованный фабричный метод в общем случае имеет следующий вид (здесь My Product и Your Product - подклассы Product):
     Параметризованный фабричный метод [C++]  ссылка
    1. class Creator {
    2. public:
    3. virtual Product* Create(Productld);
    4. };
    5.  
    6. Product* Creator::Create (Productld id) {
    7. if (id == MINE) return new MyProduct;
    8. if (id == YOURS) return new YourProduct;
    9. // выполнить для всех остальных продуктов...
    10. return 0;
    11. }

    Замещение параметризованного фабричного метода позволяет легко и избирательно расширить или заменить продукты, которые изготавливает создатель.
    Можно завести новые идентификаторы для новых видов продуктов или ассоциировать существующие идентификаторы с другими продуктами.
    Например, подкласс MyCreator мог бы переставить местами MyProduct и YourProduct для поддержки третьего подкласса Their Product:
     Замещение параметризованного фабричного метода [C++]  ссылка
    1. Product* MyCreator::Create (Productld id) {
    2. if (id == YOURS) return new MyProduct;
    3. if (id == MINE) return new YourProduct;
    4. // ! YOURS и MINE переставлены
    5. if (id == THEIRS) return new TheirProduct;
    6. // вызывается, если больше ничего не осталось
    7. return Creator::Create(id);
    8. }

    codelab.ru codelab.ru оригинал источник
  3. Использование шаблонов, чтобы не порождать подклассы.
    К сожалению, допустима ситуация, когда вам придется порождать подклассы только для того, чтобы создать подходящие объекты-продукты. В некоторых языках этого можно избежать, предоставив шаблонный подкласс класса Creator, параметризованный классом Product:
     Использование шаблонов, чтобы не порождать подклассы [C++]  ссылка
    1. class Creator {
    2. public :
    3. virtual Product* CreateProduct () = 0;
    4. };
    5.  
    6. template <class TheProduct>
    7. class StandardCreator: public Creator {
    8. public:
    9. virtual Product* CreateProduct();
    10. };
    11. template <class TheProduct>
    12. Product* StandardCreator<TheProduct>::CreateProduct () {
    13. return new TheProduct;
    14. }
    15.  
    16. /* С помощью данного шаблона клиент передает только класс продукта, по-
    17. рождать подклассы от Creator не требуется: */
    18. class MyProduct : public Product {
    19. public:
    20. MyProduct();
    21. //...
    22. };
    23. StandardCreator<MyProduct> myCreator;
    codelab.ru источник оригинал codelab.ru

codelab.ru оригинал источник codelab.ru

Результаты

Фабричные методы избавляют проектировщика от необходимости встраивать в код зависящие от приложения классы. Код имеет дело только с интерфейсом абстрактного класса Product, поэтому впоследствии он сможет работать с любыми определенными пользователями классами конкретных продуктов. источник codelab.ru codelab.ru оригинал
Потенциальный недостаток фабричного метода состоит в том, что клиентам, возможно, придется создавать подкласс класса Creator для создания одного любого нового объекта ConcreteProduct. Порождение подклассов оправдано, если клиенту так или иначе приходится создавать подклассы Creator, в противном случае клиенту придется иметь дело с дополнительным уровнем подклассов. codelab.ru источник оригинал codelab.ru
Кроме того можно выделить еще 2 последствия применения паттерна фабричный метод: codelab.ru codelab.ru источник оригинал
  1. Возможность расширения дефолтных действий.
    Создание объектов внутри класса с помощью фабричного метода всегда оказывается более гибким решением, чем непосредственное создание. Фабричный метод дает возможность подклассам наследовать реализацию каких-то действий по-умалчанию.
    В примере с документом класс Document мог бы определить конкретный(не абстрактный) фабричный метод CreateFileDialog, который создает диалоговое окно для выбора файла существующего документа. Подкласс этого класса мог бы определить специализированное для приложения диалоговое окно, заместив этот фабричный метод. В данном случае фабричный метод не является абстрактным, а содержит разумную реализацию по умолчанию. оригинал codelab.ru codelab.ru источник
  2. Соединяет параллельные иерархии.
    В примерах, которые мы рассматривали до сих пор, фабричные методы вызывались только создателем. Но это совершенно необязательно: клиенты тоже могут применять фабричные методы, особенно при наличии параллельных иерархий классов.
    Параллельные иерархии возникают в случае, когда класс делегирует часть своих обязанностей другому классу, не являющемуся производным от него. Рассмотрим, например, графические фигуры, которыми можно манипулировать интерактивно: растягивать, двигать или вращать с помощью мыши.
    Реализация таких взаимодействий с пользователем - не всегда простое дело. Часто приходится сохранять и обновлять информацию о текущем состоянии манипуляций. Но это состояние нужно только во время самой манипуляции, поэтому помещать его в объект, представляющий фигуру, не следует. К тому же фигуры ведут себя по-разному, когда пользователь манипулирует ими. Например, растягивание отрезка может сводиться к изменению положения концевой точки, а растягивание текста - к изменению междустрочных интервалов.
    При таких ограничениях лучше использовать отдельный объект-манипулятор Manipulator, который реализует взаимодействие и контролирует его текущее состояние. У разных фигур будут разные манипуляторы, являющиеся подклассом Manipulator. Получающаяся иерархия класса Manipulator параллельна (по крайней мере, частично) иерархии класса Figure.
    Класс Figure предоставляет фабричный метод CreateManipulator, который позволяет клиентам создавать соответствующий фигуре манипулятор. Подклассы Figure замещают этот метод так, чтобы он возвращал подходящий для них подкласс Manipulator. Вместо этого класс Figure может реализовать CreateManipulator так, что он будет возвращать экземпляр класса Manipulator по умолчанию, а подклассы Figure могут наследовать это умолчание. Те классы фигур, которые функционируют по описанному принципу, не нуждаются в специальном манипуляторе, поэтому иерархии параллельны только отчасти.
    Обратите внимание, как фабричный метод определяет связь между обеими иерархиями классов. В нем локализуется знание о том, какие классы способны работать совместно.  codelab.ru оригинал источник codelab.ru

  оригинал источник codelab.ru codelab.ru

Пример

Требуется автоматизировать процесс сборки компьютера из комплектующих. Т.к. каждая новая конфигурация имеет детали разных производителей – уместно сделать единый общий абстрактный класс (Creator) с различными фабричными методами, получающими отдельные детали (Product-ы) и соответственно одна общая функция собирающая все вместе: ComputerCreator.java codelab.ru codelab.ru источник оригинал

Каждый фабричный метод возвращает одну из комплектующих. Класс ComputerCreator предоставляет реализации по умолчанию, которые возвращают простейшие варианты процессора, монитора, клавиатуры: Monitor.java, Processor.java, KeyBoard.java. codelab.ru codelab.ru оригинал источник

Далее для каждой конфигурации создаем уже свои, конкретные классы (ConcreteCreator/ConcreteProduct). Т.к. в результате нам нужен пентиум с расширенной клавиатурой, то все что там нужно будет сделать, учитывая, что сборку монитора можно оставить прежней это 3 класса, 1 Creator и 2 новых продукта: PentiumCreator.java, KeyBoardFull.java, Processor64.java. codelab.ru оригинал codelab.ru источник

Ну а если завтра нам понадобится более экономичный вариант AMD с ЖК дисплеем, мы осуществим это через AMDCreator: AMDCreator.java, AMDSempron.java, LSDMonitor.java. источник codelab.ru оригинал codelab.ru

Обратите внимание, что опять же, так фабричные методы не абстрактны мы имели замечательную возможность не дублировать новый метод создания клавиатуры, а наследовать уже имеющийся, потому что этот вариант по-умалчанию нас вполне устраивает. codelab.ru источник оригинал codelab.ru



Реализации: java(10)   +добавить реализацию

1) ComputerCreator.java, code #420[автор:this]
2) Monitor.java, code #421[автор:this]
3) Processor.java, code #422[автор:this]
4) KeyBoard.java, code #423[автор:this]
5) PentiumCreator.java, code #425[автор:this]
6) KeyBoardFull.java, code #426[автор:this]
7) Processor64.java, code #427[автор:this]
8) AMDCreator.java, code #428[автор:this]
9) AMDSempron.java, code #429[автор:this]
10) LSDMonitor.java, code #430[автор:this]


<< назад наверх
распечатать обсудить >>

 
каталог | задачи | паттерны | исходники | стат | форумы | карта сайта | контакты | ссылки 
© 2000-2017 CodeLAB Group
  Все права защищены
Страница сгенерирована за 0.029565 секунд
Количество запросов к БД: 14, gzip: 19.7kb/109.3kb(83%)