Абстрактный узор фабрики

Шаблон проектирования программного обеспечения
Диаграмма классов UML

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

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

Обзор

Шаблон проектирования абстрактной фабрики — один из 23 шаблонов, описанных в книге Design Patterns 1994 года . Он может быть использован для решения таких проблем, как: [3]

  • Как приложение может быть независимым от способа создания его объектов?
  • Как класс может быть независимым от того, как создаются требуемые ему объекты?
  • Как можно создать семейства связанных или зависимых объектов?

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

Фабрика — это местоположение конкретного класса в коде, в котором конструируются объекты . Реализация шаблона направлена ​​на то, чтобы изолировать создание объектов от их использования и создавать семейства связанных объектов вне зависимости от их конкретных классов. [2] Это позволяет вводить новые производные типы без изменения кода, использующего базовый класс .

Шаблон описывает, как решать такие проблемы:

  • Инкапсулируйте создание объекта в отдельный (фабричный) объект, определив и реализовав интерфейс для создания объектов.
  • Делегируйте создание объектов фабричным объектам вместо того, чтобы создавать объекты напрямую.

Это делает класс независимым от того, как создаются его объекты. Класс может быть сконфигурирован с помощью объекта фабрики, который он использует для создания объектов, и объект фабрики может быть заменен во время выполнения.


Определение

Шаблоны проектирования описывают абстрактный шаблон фабрики как «интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов». [4]

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

Фабрика определяет конкретный тип создаваемого объекта, и именно здесь объект фактически создается. Однако фабрика возвращает только ссылку (в Java, например, оператором new ) или указатель абстрактного типа на созданный конкретный объект.

Это изолирует клиентский код от создания объектов , поскольку клиенты запрашивают у объекта-фабрики создание объекта требуемого абстрактного типа и возвращают абстрактный указатель на объект. [5]

Примером может служить абстрактный класс фабрики DocumentCreator, который предоставляет интерфейсы для создания ряда продуктов (например, createLetter()и createResume()). Система будет иметь любое количество производных конкретных версий класса, DocumentCreatorтаких как FancyDocumentCreatorили ModernDocumentCreator, каждая с различной реализацией createLetter()и , createResume()которые будут создавать соответствующие объекты, такие как FancyLetterили ModernResume. Каждый из этих продуктов является производным от простого абстрактного класса, такого как Letterили Resume, о котором клиент знает. Клиентский код получит соответствующий экземплярDocumentCreator и вызовет его методы фабрики . Каждый из полученных объектов будет создан из одной и той же DocumentCreatorреализации и будет иметь общую тему. Клиенту нужно будет знать только, как обращаться с абстрактным Letterили Resumeклассом, а не с конкретной версией, созданной конкретной фабрикой.

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

  • Клиентский код не имеет знаний о конкретном типе , не нуждаясь во включении каких-либо заголовочных файлов или объявлений классов , связанных с ним. Клиентский код имеет дело только с абстрактным типом. Объекты конкретного типа действительно создаются фабрикой, но клиентский код получает доступ к таким объектам только через их абстрактные интерфейсы . [6]
  • Добавление новых конкретных типов выполняется путем изменения клиентского кода для использования другой фабрики, изменение, которое обычно представляет собой одну строку в одном файле. Затем другая фабрика создает объекты другого конкретного типа, но по-прежнему возвращает указатель того же абстрактного типа, что и раньше, тем самым изолируя клиентский код от изменений. Это значительно проще, чем изменение клиентского кода для создания экземпляра нового типа. Для этого потребуется изменить каждое место в коде, где создается новый объект, а также убедиться, что все такие места кода имеют информацию о новом конкретном типе, например, путем включения файла заголовка конкретного класса. Если все объекты фабрики хранятся глобально в объекте singleton , и весь клиентский код проходит через singleton для доступа к надлежащей фабрике для создания объекта, то изменение фабрик так же просто, как изменение объекта singleton. [6]

Структура

UML-диаграмма

Пример класса UML и диаграммы последовательности для шаблона проектирования абстрактной фабрики. [7]
Пример класса UML и диаграммы последовательности для шаблона проектирования абстрактной фабрики. [7]

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

Диаграмма последовательности UML показывает взаимодействия во время выполнения. Объект вызывает объект , который создает и возвращает объект. После этого вызывает , который создает и возвращает объект.ClientcreateProductA()Factory1ProductA1ClientcreateProductB()Factory1ProductB1

Варианты

Первоначальная структура шаблона абстрактной фабрики, как определено в 1994 году в Design Patterns , основана на абстрактных классах для абстрактной фабрики и абстрактных продуктов, которые должны быть созданы. Конкретные фабрики и продукты являются классами, которые специализируют абстрактные классы с использованием наследования. [4]

Более поздняя структура шаблона основана на интерфейсах, которые определяют абстрактную фабрику и абстрактные продукты, которые должны быть созданы. Эта конструкция использует собственную поддержку интерфейсов или протоколов в основных языках программирования, чтобы избежать наследования. В этом случае конкретные фабрики и продукты являются классами, которые реализуют интерфейс, реализуя его. [1]

Пример

Данная реализация C++23 основана на реализации, описанной в книге до C++98.

импорт стандартный ; enum class Направление { Север , Юг , Восток , Запад };      класс MapSite { public : virtual void enter () = 0 ; virtual ~ MapSite () = default ; };           class Room : public MapSite { public : Room () : roomNumber ( 0 ) {} Room ( int n ) : roomNumber ( n ) {} void setSide ( Direction d , MapSite * ms ) { std :: println ( "Room::setSide {} ms" , d ); } virtual void enter () {} Room ( const Room & ) = delete ; // правило трех Room & оператор = ( const Room & ) = delete ; private : int roomNumber ; };                                    класс Стена : public MapSite { public : Стена () {} virtual void enter () {} };          class Door : public MapSite { public : Door ( Room * r1 = nullptr , Room * r2 = nullptr ) : room1 ( r1 ), room2 ( r2 ) {} virtual void enter () {} Door ( const Door & ) = delete ; // правило трех Door & оператор = ( const Door & ) = delete ; private : Room * room1 ; Room * room2 ; };                                 class Maze { public : void addRoom ( Room * r ) { std :: println ( "Maze::addRoom {}" , r ); } Room * roomNo ( int ) const { return nullptr ; } };                класс MazeFactory { public : MazeFactory () = default ; virtual ~ MazeFactory () = default ;          виртуальный лабиринт * makeMaze () const { return new лабиринт ; } виртуальная стена * makeWall () const { return new стена ; } виртуальная комната * makeRoom ( int n ) const { return new комната ( n ); } виртуальная дверь * makeDoor ( комната * r1 , комната * r2 ) const { return new дверь ( r1 , r2 ); } };                                        // Если createMaze передается объект в качестве параметра для создания комнат, стен и дверей, то можно изменить классы комнат, стен и дверей, передав другой параметр. Это пример шаблона Abstract Factory (99).class MazeGame { public : Maze * createMaze ( MazeFactory & factory ) { Maze * aMaze = factory.makeMaze ( ) ; Room * r1 = factory.makeRoom ( 1 ); Room * r2 = factory.makeRoom ( 2 ) ; Door * aDoor = factory.makeDoor ( r1 , r2 ) ; aMaze - > addRoom ( r1 ); aMaze - > addRoom ( r2 ); r1 -> setSide ( Direction :: North , factory.makeWall ()); r1 - > setSide ( Direction :: East , aDoor ) ; r1 - > setSide ( Direction :: South , factory.makeWall ( ) ); r1 - > setSide ( Direction :: West , factory.makeWall ( )); r2 - > setSide ( Direction :: North , factory.makeWall ( ) ) ; r2 -> setSide ( Направление :: Восток , factory.makeWall ()); r2 - > setSide ( Направление :: Юг , factory.makeWall ( ) ); r2 - > setSide ( Направление :: Запад , aDoor ); return aMaze ; } } ;                                            int main ( ) { MazeGame game ; MazeFactory factory ; game.createMaze ( factory ) ; }       

Вывод программы:

Maze::addRoom 0x1317ed0 Maze::addRoom 0x1317ef0 Room::setSide 0 0x1318340 Room::setSide 2 0x1317f10 Room::setSide 1 0x1318360 Room::setSide 3 0x1318380 Room::setSide 0 0x13183a0 Room::setSide 2 0x13183c0 Room::setSide 1 0x13183e0 Room::setSide 3 0x1317f10

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

Ссылки

  1. ^ abc Freeman, Eric; Robson, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (ред.). Head First Design Patterns (мягкая обложка) . Том 1. O'REILLY. стр. 156. ISBN 978-0-596-00712-6. Получено 12.09.2012 .
  2. ^ ab Freeman, Eric; Robson, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (ред.). Head First Design Patterns (мягкая обложка) . Том 1. O'REILLY. стр. 162. ISBN 978-0-596-00712-6. Получено 12.09.2012 .
  3. ^ "Шаблон проектирования Абстрактная фабрика - проблема, решение и применимость". w3sDesign.com . Получено 11 августа 2017 г.
  4. ^ ab Gamma, Erich; Richard Helm; Ralph Johnson; John M. Vlissides (2009-10-23). ​​"Design Patterns: Abstract Factory". informIT. Архивировано из оригинала 2012-05-16 . Получено 2012-05-16 . Создание объектов: Абстрактная фабрика: Цель: Предоставить интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.{{cite web}}: CS1 maint: бот: исходный статус URL неизвестен ( ссылка )
  5. ^ Veeneman, David (2009-10-23). ​​«Объектный дизайн для озадаченных». The Code Project. Архивировано из оригинала 2011-02-21 . Получено 2012-05-16 . Фабрика изолирует клиента от изменений в продукте или способе его создания, и она может обеспечить эту изоляцию для объектов, полученных из очень разных абстрактных интерфейсов.{{cite web}}: CS1 maint: бот: исходный статус URL неизвестен ( ссылка )
  6. ^ ab "Abstract Factory: Implementation". OODesign.com . Получено 2012-05-16 .
  7. ^ "Шаблон проектирования Абстрактная фабрика - Структура и сотрудничество". w3sDesign.com . Получено 2017-08-12 .
  • Медиа, связанные с Abstract factory на Wikimedia Commons
  • Абстрактная фабрика Пример реализации абстрактной фабрики
Получено с "https://en.wikipedia.org/w/index.php?title=Abstract_factory_pattern&oldid=1265430540"