stringtranslate.com

Шаблон фабричного метода

В объектно-ориентированном программировании шаблон фабричного метода — это шаблон проектирования , который использует фабричные методы для решения проблемы создания объектов без указания их точного класса . Вместо вызова конструктора это делается путем вызова фабричного метода для создания объекта. Фабричные методы могут быть либо указаны в интерфейсе и реализованы дочерними классами, либо реализованы в базовом классе и при необходимости переопределены производными классами . Это один из 23 классических шаблонов проектирования, описанных в книге « Шаблоны проектирования» (часто называемых «Бандой четырех» или просто «GoF»), который относится к подкатегории « творческий шаблон» . [1]

Обзор

Шаблон проектирования «Фабричный метод» решает такие проблемы, как:

Шаблон проектирования «Фабричный метод» описывает, как решать такие проблемы:

Это позволяет писать подклассы, которые могут изменить способ создания объекта (например, путем переопределения класса для создания экземпляра).
См. также диаграмму классов UML ниже.

Определение

«Определите интерфейс для создания объекта, но позвольте подклассам решать, какой класс создавать. Метод Factory позволяет классу отложить создание экземпляра, который он использует, до подклассов». ( Банда из четырех )

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

Шаблон фабричного метода опирается на наследование, поскольку создание объектов делегируется подклассам, которые реализуют фабричный метод для создания объектов. [2] Как показано в примере C# ниже, шаблон фабричного метода также может опираться на интерфейс — в данном случае IPerson — для реализации.

Состав

Диаграмма классов UML

Пример диаграммы классов UML для шаблона проектирования «Фабричный метод». [3]

На приведенной выше диаграмме классов UML класс , которому требуется объект, не создает экземпляр класса напрямую. Вместо этого ссылается на отдельный объект для создания объекта продукта, что делает независимость от того, какой конкретный класс создается. Подклассы могут переопределить, какой класс создавать. В этом примере подкласс реализует абстрактное, создавая экземпляр класса.CreatorProductProduct1CreatorfactoryMethod()CreatorCreatorCreator1factoryMethod()Product1

Примеры

Эта реализация C++14 основана на реализации до C++98, описанной в книге. [4]

#include <iostream> #include <память>  enum ProductId { МОЙ , ВАШ };   // определяет интерфейс объектов, создаваемых фабричным методом. класс Product { public : virtual void print () = 0 ; виртуальный ~ Продукт () = по умолчанию ; };           // реализует интерфейс продукта. класс ConcreteProductMINE : public Product { public : void print () { std :: cout << "this=" << this << " print MINE \n " ; } };               // реализует интерфейс продукта. класс ConcreteProduct YOURS : public Product { public : void print () { std :: cout << "this=" << this << " распечатайте ВАШЕ \n " ; } };               // объявляет фабричный метод, который возвращает объект типа Product. class Creator { public : virtual std :: unique_ptr <Product> create ( ProductId id ) { if ( ProductId :: MINE == id ) return std :: make_unique < ConcreteProductMINE > ( ) ; if ( ProductId :: YOURS == id ) return std :: make_unique < ConcreteProduct YOURS > (); // повторяем для остальных продуктов...                     вернуть нульптр ; } виртуальный ~ Создатель () = по умолчанию ; };      int main () { // unique_ptr предотвращает утечку памяти. std :: unique_ptr < Создатель > создатель = std :: make_unique < Создатель > (); std :: unique_ptr < Продукт > продукт = создатель -> создать ( ProductId :: MINE ); продукт -> печать ();             продукт = создатель -> создать ( ProductId :: ВАШ ); продукт -> печать (); }   

Вывод программы такой

this = 0x6e5e90 напечатайте МОЁ this = 0x6e62c0 напечатайте ВАШЕ    

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

Состав

Roomявляется базовым классом для конечного продукта ( MagicRoomили OrdinaryRoom). MazeGameобъявляет абстрактный фабричный метод для производства такого базового продукта. MagicRoomи OrdinaryRoomявляются подклассами базового продукта, реализующими конечный продукт. MagicMazeGameи OrdinaryMazeGameявляются подклассами MazeGameреализации фабричного метода производства конечной продукции. Таким образом, фабричные методы отделяют вызывающие объекты ( MazeGame) от реализации конкретных классов. Это делает «нового» Оператора ненужным, позволяет придерживаться принципа открытости/закрытости и делает конечный продукт более гибким в случае изменений.

Пример реализации

С#

// Пустой словарь фактического объекта public интерфейс IPerson { string GetName (); }    public class Villager : IPerson { public string GetName () { return "Village Person" ; } }           общественный класс CityPerson : IPerson { public string GetName () { return "City Person" ; } }           public enum PersonType { Сельский , Городской }    /// <summary> /// Реализация Factory — используется для создания объектов. /// </summary> общественный класс PersonFactory { общественный IPerson GetPerson ( тип PersonType ) { переключатель ( тип ) { case PersonType . Сельский : вернуть нового жителя (); случай PersonType . Urban : вернуть нового CityPerson (); по умолчанию : создать новое исключение NotSupportedException (); } } }                          

В приведенном выше коде вы можете увидеть создание одного интерфейса под названием IPersonи двух реализаций под названием Villagerи CityPerson. В зависимости от типа, переданного в PersonFactoryобъект, мы возвращаем исходный конкретный объект в качестве интерфейса IPerson.

Фабричный метод — это просто дополнение к PersonFactoryклассу. Он создает объект класса через интерфейсы, но, с другой стороны, он также позволяет подклассу решать, экземпляр какого класса создается.

общедоступный интерфейс IProduct { строка GetName (); bool SetPrice ( двойная цена ); }       Телефон общественного класса : IProduct { частное двойное _price ;        public string GetName () { return «Apple TouchPad» ; }       public bool SetPrice ( двойная цена ) { _price = цена ; вернуть истину ; } }          /* Почти то же самое, что и Factory, только дополнительная возможность сделать что-то с созданным методом */ public Abstract class ProductAbstractFactory { protected Abstract IProduct MakeProduct ();        public IProduct GetObject () // Реализация фабричного метода. { вернуть это . СделатьПродукт (); } }       общественный класс PhoneConcreteFactory : ProductAbstractFactory { защищенное переопределение IProduct MakeProduct () { продукт IProduct = новый телефон (); // Сделайте что-нибудь с объектом после того, как получите его. продукт . УстановитьЦена ( 20.30 ); возврат товара ; } }                   

Вы можете видеть, что мы использовали MakeProductв бетонной фабрике. В результате вы можете легко позвонить MakeProduct()с него, чтобы получить файл IProduct. Вы также можете написать свою собственную логику после получения объекта в конкретном фабричном методе. GetObject сделан абстрактным в интерфейсе Factory.

Джава

Этот пример Java похож на пример из книги « Шаблоны проектирования» .

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

публичный абстрактный класс Room { Abstract void Connect ( Room room ); }        общественный класс MagicRoom расширяет комнату { public void Connect ( комната комната ) { } }          общественный класс OrdinaryRoom расширяет комнату { public void Connect ( комната комната ) { } }          публичный абстрактный класс MazeGame { частный окончательный список < Комната > комнаты = новый ArrayList <> ();            public MazeGame () { Комната room1 = makeRoom (); Комната комната2 = makeRoom (); комната1 . подключиться ( комната2 ); номера . добавить ( комната1 ); номера . добавить ( комната2 ); }               абстрактная защищенная комната makeRoom (); }   

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

общественный класс MagicMazeGame расширяет MazeGame { @Override protected MagicRoom makeRoom () { return new MagicRoom (); } }              общественный класс OrdinaryMazeGame расширяет MazeGame { @Override protected OrdinaryRoom makeRoom () { return new OrdinaryRoom (); } }              MazeGame обычная игра = новая обычная игра Maze (); MazeGame MagicGame = новая MagicMazeGame ();        

PHP

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

/* Заводские и автомобильные интерфейсы */интерфейс  CarFactory {  public  function  makeCar () :  Car ; }интерфейс  Car {  общественная  функция  getType () :  строка ; }/* Конкретные реализации фабрики и автомобиля */класс  SedanFactory  реализует  CarFactory {  public  function  makeCar () :  Car  {  return  new  Sedan ();  } }класс  Sedan  реализует  Car {  public  function  getType () :  string  {  return  'Sedan' ;  } }/* Клиент */$фабрика  =  новый  SedanFactory (); $car  =  $factory -> makeCar (); напечатайте  $car -> getType ();

Питон

То же, что и пример Java.

из  abc  импорт  ABC ,  абстрактный методкласс  MazeGame ( ABC ):  def  __init__ ( self )  ->  None :  self . комнаты  =  []  self . _prepare_rooms () def  _prepare_rooms ( self )  ->  Нет :  room1  =  self . make_room ()  комната2  =  self . освободить место () комната1 . подключиться ( комната2 )  самостоятельно . номера . добавить ( room1 )  self . номера . добавить ( комната2 ) def  play ( self )  ->  None :  print ( f "Игра с использованием { self.rooms [ 0 ] } " ) @abstractmethod  def  make_room ( self ):  поднять  NotImplementedError ( «Вы должны реализовать это!» )класс  MagicMazeGame ( MazeGame ):  def  make_room ( self )  ->  «MagicRoom» :  return  MagicRoom ()класс  OrdinaryMazeGame ( MazeGame ):  def  make_room ( self )  ->  «OrdinaryRoom» :  return  OrdinaryRoom ()class  Room ( ABC ):  def  __init__ ( self )  ->  None :  self . подключенные_комнаты  =  [] def  Connect ( self ,  room :  «Комната» )  ->  Нет :  self . подключенные_комнаты . добавить ( комната )класс  MagicRoom ( Комната ):  def  __str__ ( self )  ->  str :  вернуть  «Волшебную комнату»класс  OrdinaryRoom ( Комната ):  def  __str__ ( self )  ->  str :  return  «Обычная комната»обычная игра  =  Обычная игра в лабиринте () обычная игра . играть ()MagicGame  =  MagicMazeGame () MagicGame . играть ()

Использование

Смотрите также

Примечания

  1. ^ Гамма и др. 1994, с. 107.
  2. ^ Фриман, Эрик; Фриман, Элизабет; Кэти, Сьерра; Берт, Бейтс (2004). Хендриксон, Майк; Лукидес, Майк (ред.). Шаблоны проектирования Head First (мягкая обложка) . Том. 1. О'РЕЙЛИ. п. 162. ИСБН 978-0-596-00712-6. Проверено 12 сентября 2012 г.
  3. ^ «Шаблон проектирования фабричного метода - структура и сотрудничество» . w3sDesign.com . Проверено 12 августа 2017 г.
  4. ^ Гамма и др. 1994, с. 122.

Рекомендации

Внешние ссылки