stringtranslate.com

Фабричный метод шаблона

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

Обзор

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

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

Определение

Согласно Design Patterns: Elements of Reusable Object-Oriented Software : «Определите интерфейс для создания объекта, но позвольте подклассам решать, какой класс создавать. Метод Factory позволяет классу откладывать создание используемого им экземпляра подклассам». [2]

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

Шаблон метода фабрики опирается на наследование, поскольку создание объектов делегируется подклассам, которые реализуют метод фабрики для создания объектов. [3] Шаблон также может опираться на реализацию интерфейса .

Структура

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

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

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

Примеры

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

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

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

это = 0x6e5e90 распечатать МОЕ это = 0x6e62c0 распечатать ВАШЕ    

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

Структура

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

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

С#

// Пустой словарь реального объекта public interface IPerson { string GetName (); }    public class Villager : IPerson { public string GetName () { return "Village Person" ; } }           public class CityPerson : IPerson { public string GetName () { return "Городской человек" ; } }           public enum PersonType { Сельский , Городской }    /// <summary> /// Реализация Factory - используется для создания объектов. /// </summary> public class PersonFactory { public IPerson GetPerson ( PersonType type ) { switch ( type ) { case PersonType.Rural : return new Villager (); case PersonType.Urban : return new CityPerson ( ) ; default : throw new NotSupportedException ( ) ; } } }                          

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

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

открытый интерфейс IProduct { string GetName (); bool SetPrice ( double price ); }       публичный класс Телефон : IProduct { частный double _price ;        public string GetName () { return "Apple TouchPad" ; }       public bool SetPrice ( double price ) { _price = price ; return true ; } }          /* Почти то же самое, что и Factory, просто дополнительная возможность что-то сделать с созданным методом */ public abstract class ProductAbstractFactory { protected abstract IProduct MakeProduct ();        public IProduct GetObject () // Реализация метода Factory. { return this . MakeProduct (); } }       public class PhoneConcreteFactory : ProductAbstractFactory { protected override IProduct MakeProduct () { IProduct product = new Phone (); // Сделать что -нибудь с объектом после его получения product.SetPrice ( 20.30 ) ; return product ; } }                   

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

Ява

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

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

public abstract class Room { abstract void connect ( Room room ); }        открытый класс MagicRoom расширяет Room { public void connect ( Room room ) {} }          открытый класс OrdinaryRoom расширяет Room { public void connect ( Room room ) {} }          public abstract class MazeGame { private final List < Room > rooms = new ArrayList <> ();            public MazeGame ( ) { Комната room1 = makeRoom ( ); Комната room2 = makeRoom () ; room1.connect ( room2 ) ; rooms.add ( room1 ) ; rooms.add ( room2 ) ; }               абстрактный защищенный Room makeRoom (); }   

Конструктор MazeGame— это шаблонный метод , который добавляет некоторую общую логику. Он ссылается на makeRoom()метод фабрики, который инкапсулирует создание комнат таким образом, что другие комнаты могут использоваться в подклассе. Для реализации другого игрового режима, в котором есть магические комнаты, makeRoomметод может быть переопределен:

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

PHP

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

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

Питон

В этом примере на Python используется то же самое, что и в предыдущем примере на Java.

из  abc  импорт  ABC ,  абстрактный методкласс  MazeGame ( ABC ):  def  __init__ ( self )  ->  None :  self . Rooms  =  []  self . _prepare_ Rooms () def  _prepare_rooms ( self )  -  > None :  room1  =  self.make_room ( ) room2 = self.make_room ( )    room1.connect ( room2 ) self.rooms.append ( room1 ) self.rooms.append ( room2 )   def  play ( self )  ->  None :  print ( f "Игра с использованием { self . Rooms [ 0 ] } " ) @abstractmethod  def  make_room ( self ):  raise  NotImplementedError ( "Вы должны реализовать это!" )класс  MagicMazeGame ( MazeGame ):  def  make_room ( self )  ->  "MagicRoom" :  return  MagicRoom ()класс  OrdinaryMazeGame ( MazeGame ):  def  make_room ( self )  ->  "OrdinaryRoom" :  return  OrdinaryRoom ()класс  Комната ( ABC ):  def  __init__ ( self )  ->  None :  self . connected_rooms  =  [] def  connect ( self ,  room :  "Комната" )  ->  None :  self . connected_rooms . append ( комната )класс  MagicRoom ( Комната ):  def  __str__ ( self )  ->  str :  return  "Волшебная комната"класс  OrdinaryRoom ( Room ):  def  __str__ ( self )  ->  str :  return  "Обычная комната"обычнаяИгра  =  ОбычнаяИграЛабиринт () обычнаяИгра . играть ()magicGame  =  MagicMazeGame () magicGame . play ()

Использует

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

Примечания

  1. ^ Гамма и др. 1994, стр. 107.
  2. ^ Гамма, Эрих ; Хелм, Ричард ; Джонсон, Ральф ; Влиссидес, Джон (1994). Шаблоны проектирования: элементы повторно используемого объектно-ориентированного программного обеспечения . Addison-Wesley. ISBN 0-201-63361-2.
  3. ^ Фримен, Эрик; Фримен, Элизабет; Кэти, Сьерра; ​​Берт, Бейтс (2004). Хендриксон, Майк; Лукидес, Майк (ред.). Head First Design Patterns (мягкая обложка) . Том 1. O'REILLY. стр. 162. ISBN 978-0-596-00712-6. Получено 12.09.2012 .
  4. ^ "Шаблон проектирования Factory Method - Структура и сотрудничество". w3sDesign.com . Получено 2017-08-12 .
  5. ^ Гамма и др. 1994, стр. 122.

Ссылки

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