Jump to content

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

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

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

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

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

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

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

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

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

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

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

Определение

[ редактировать ]

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

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

[ редактировать ]

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

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

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

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

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

Структура

[ редактировать ]

UML-диаграмма

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

На приведенной выше UML классов диаграмме тот Client класс, который требует ProductA и ProductB объекты не создают экземпляры ProductA1 и ProductB1 занятия напрямую. Вместо этого Client относится к AbstractFactory интерфейс для создания объектов, что делает Client независимо от того, как создаются объекты (какие конкретные классы создаются). Factory1 класс реализует AbstractFactory интерфейс путем создания экземпляра ProductA1 и ProductB1 занятия.

Диаграмма UML последовательности показывает взаимодействие во время выполнения. Client вызовы объектов createProductA() на Factory1 объект, который создает и возвращает ProductA1 объект. После этого Client звонки createProductB() на Factory1, который создает и возвращает ProductB1 объект.

Варианты

[ редактировать ]

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

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

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

#include <iostream>

enum Direction {North, South, East, West};

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::cout << "Room::setSide " << d << ' ' << ms << '\n';
  }
  virtual void enter() {}
  Room(const Room&) = delete; // rule of three
  Room& operator=(const Room&) = delete;
private:
  int roomNumber;
};

class Wall : public MapSite {
public:
  Wall() {}
  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; // rule of three
  Door& operator=(const Door&) = delete;
private:
  Room* room1;
  Room* room2;
};

class Maze {
public:
  void addRoom(Room* r) {
    std::cout << "Maze::addRoom " << r << '\n';
  }
  Room* roomNo(int) const {
    return nullptr;
  }
};

class MazeFactory {
public:
  MazeFactory() = default;
  virtual ~MazeFactory() = default;

  virtual Maze* makeMaze() const {
    return new Maze;
  }
  virtual Wall* makeWall() const {
    return new Wall;
  }
  virtual Room* makeRoom(int n) const {
    return new Room(n);
  }
  virtual Door* makeDoor(Room* r1, Room* r2) const {
    return new Door(r1, r2);
  }
};

// If createMaze is passed an object as a parameter to use to create rooms, walls, and doors, then you can change the classes of rooms, walls, and doors by passing a different parameter. This is an example of the Abstract Factory (99) pattern.

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(North, factory.makeWall());
    r1->setSide(East, aDoor);
    r1->setSide(South, factory.makeWall());
    r1->setSide(West, factory.makeWall());
    r2->setSide(North, factory.makeWall());
    r2->setSide(East, factory.makeWall());
    r2->setSide(South, factory.makeWall());
    r2->setSide(West, 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. ^ Jump up to: а б с Фриман, Эрик; Робсон, Элизабет; Сьерра, Кэти; Бейтс, Берт (2004). Хендриксон, Майк; Лукидес, Майк (ред.). Шаблоны проектирования Head First (мягкая обложка) . Том. 1. О'РЕЙЛИ. п. 156. ИСБН  978-0-596-00712-6 . Проверено 12 сентября 2012 г.
  2. ^ Jump up to: а б Фриман, Эрик; Робсон, Элизабет; Сьерра, Кэти; Бейтс, Берт (2004). Хендриксон, Майк; Лукидес, Майк (ред.). Шаблоны проектирования Head First (мягкая обложка) . Том. 1. О'РЕЙЛИ. п. 162. ИСБН  978-0-596-00712-6 . Проверено 12 сентября 2012 г.
  3. ^ «Шаблон проектирования «Абстрактная фабрика» — проблема, решение и применимость» . w3sDesign.com . Проверено 11 августа 2017 г.
  4. ^ Jump up to: а б Гамма, Эрих; Ричард Хелм; Ральф Джонсон; Джон М. Влиссидес (23 октября 2009 г.). «Шаблоны проектирования: абстрактная фабрика» . ИнформИТ. Архивировано из оригинала 16 мая 2012 г. Проверено 16 мая 2012 г. Создание объектов: Абстрактная фабрика: Цель: предоставить интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов. {{cite web}}: CS1 maint: bot: исходный статус URL неизвестен ( ссылка )
  5. ^ Винеман, Дэвид (23 октября 2009 г.). «Предметный дизайн для недоумевающих» . Проект Кодекса. Архивировано из оригинала 21 февраля 2011 г. Проверено 16 мая 2012 г. Фабрика изолирует клиента от изменений в продукте или способе его создания и может обеспечить эту изоляцию между объектами, полученными из самых разных абстрактных интерфейсов. {{cite web}}: CS1 maint: bot: исходный статус URL неизвестен ( ссылка )
  6. ^ Jump up to: а б «Абстрактная фабрика: реализация» . OODesign.com . Проверено 16 мая 2012 г.
  7. ^ «Шаблон проектирования «Абстрактная фабрика» — структура и сотрудничество» . w3sDesign.com . Проверено 12 августа 2017 г.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 7a97166859285739bcc7ea006c516e11__1713680460
URL1:https://arc.ask3.ru/arc/aa/7a/11/7a97166859285739bcc7ea006c516e11.html
Заголовок, (Title) документа по адресу, URL1:
Abstract factory pattern - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)