Абстрактный заводской узор - Abstract factory pattern

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

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

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

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

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

Обзор

Шаблон проектирования Абстрактная фабрика - один из двадцати трех хорошо известных шаблонов проектирования GoF, которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, протестировать и т. Д. и повторное использование.

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

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

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

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

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

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

Определение

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

Применение

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

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

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

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

Состав

Диаграмма UML

Пример диаграммы классов Метод createButton в интерфейсе GUIFactory возвращает объекты типа Button.  Какая реализация Button будет возвращена, зависит от того, какая реализация GUIFactory обрабатывает вызов метода.
Класс пример Диаграмма Способ createButtonпо GUIFactoryвозвращений интерфейса объектов типа Button. Какая реализация Buttonбудет возвращена, зависит от того, какая реализация GUIFactoryобрабатывает вызов метода.
Пример класса UML и диаграммы последовательности для шаблона проектирования Абстрактная фабрика.  [8]
Пример класса UML и диаграммы последовательности для шаблона проектирования Абстрактная фабрика.

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

Диаграмма LePUS3

Пример Python

from abc import ABC, abstractmethod
from sys import platform


class Button(ABC):
    @abstractmethod
    def paint(self):
        pass


class LinuxButton(Button):
    def paint(self):
        return "Render a button in a Linux style"


class WindowsButton(Button):
    def paint(self):
        return "Render a button in a Windows style"


class MacOSButton(Button):
    def paint(self):
        return "Render a button in a MacOS style"


class GUIFactory(ABC):
    @abstractmethod
    def create_button(self):
        pass


class LinuxFactory(GUIFactory):
    def create_button(self):
        return LinuxButton()


class WindowsFactory(GUIFactory):
    def create_button(self):
        return WindowsButton()


class MacOSFactory(GUIFactory):
    def create_button(self):
        return MacOSButton()


if platform == "linux":
    factory = LinuxFactory()
elif platform == "darwin":
    factory = MacOSFactory()
elif platform == "win32":
    factory = WindowsFactory()
else:
    raise NotImplementedError(f"Not implemented for your platform: {platform}")

button = factory.create_button()
result = button.paint()
print(result)

Альтернативная реализация с использованием самих классов как фабрик:

from abc import ABC, abstractmethod
from sys import platform


class Button(ABC):
    @abstractmethod
    def paint(self):
        pass


class LinuxButton(Button):
    def paint(self):
        return "Render a button in a Linux style"


class WindowsButton(Button):
    def paint(self):
        return "Render a button in a Windows style"


class MacOSButton(Button):
    def paint(self):
        return "Render a button in a MacOS style"


if platform == "linux":
    factory = LinuxButton
elif platform == "darwin":
    factory = MacOSButton
elif platform == "win32":
    factory = WindowsButton
else:
    raise NotImplementedError(f"Not implemented for your platform: {platform}")

button = factory()
result = button.paint()
print(result)

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

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

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