Обзор шаблона проектирования Абстрактная фабрика и его реализация в Dart и Flutter

В прошлой статье я проанализировал шаблон проектирования Factory Method. На этот раз я хотел бы проанализировать и реализовать шаблон проектирования ООП, который имеет аналогичное назначение, даже похожее имя, но более гибкий и лучше подходит для структуры больших проектов, чем шаблон проектирования фабричный метод - это абстрактная фабрика.

Оглавление

  • Что такое шаблон проектирования "Абстрактная фабрика"?
  • Анализ
  • Реализация
  • Другие статьи из этой серии
  • Ваш вклад

Что такое шаблон проектирования "Абстрактная фабрика"?

Абстрактная фабрика - это творческий шаблон проектирования, также известный как Комплект. Его намерение в книге GoF описывается так:

Предоставьте интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.

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

Если вы следите за этой серией, я думаю, вы только что почувствовали дежавю, не так ли? Шаблон проектирования Factory Method имеет почти то же намерение и цель. Да, это правда, просто так. Но почему тогда существует отдельный заводской паттерн? Основное различие между этими двумя шаблонами заключается в том, что шаблон Абстрактная фабрика позволяет создать семейство связанных объектов - одна фабрика отвечает за создание нескольких объектов. В результате вам не нужно предоставлять отдельную фабрику для каждого конкретного класса / компонента. Фактически, вы можете рассматривать шаблон проектирования Factory Method как подмножество шаблона абстрактной фабрики - абстрактная фабрика состоит из нескольких фабричных методов, каждый из которых создает только один конкретный объект.

Шаблон проектирования Абстрактная фабрика делает создание объектов более гибким:

  • Гибкость во время компиляции - способ создания объектов может быть реализован и изменен независимо от клиентов путем определения новых (подклассов);
  • Гибкость во время выполнения - класс может быть сконфигурирован с фабричным объектом, который он использует для создания объектов, и даже более того, фабричный объект может быть заменен динамически.

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

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

Анализ

Общая структура шаблона проектирования Абстрактная фабрика выглядит следующим образом:

  • Абстрактная фабрика - объявляет интерфейс операций, создающих абстрактные объекты Product;
  • Concrete Factory - реализует операции по созданию объектов Concrete Product. Каждому бетонному заводу соответствует только один вариант продукции;
  • Продукт - объявляет интерфейс для типа объекта Продукт;
  • Concrete Product - реализует интерфейс Product и определяет объект продукта, который должен быть создан соответствующей Concrete Factory;
  • Клиент - использует только интерфейсы, объявленные классами Abstract Factory и Product.

Применимость

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

Реализация

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

Несмотря на то, что вы используете одну и ту же базу кода с Flutter, обычно требуется, чтобы компоненты пользовательского интерфейса выглядели по-разному на разных платформах. Самый простой вообразимый вариант использования в контексте Flutter - отображение виджетов в стиле Material или Cupertino в зависимости от того, используете ли вы соответственно устройство Android или iOS.

В прошлый раз мы решили эту проблему, добавив в наш код шаблон проектирования Factory Method и предоставив отдельную фабрику для каждого компонента, зависящего от платформы, который динамически создает требуемый виджет после проверки текущей платформы, тем самым отделяя бизнес-логику от уровня представления. (UI). Однако такой подход становится огромной головной болью, когда существует несколько компонентов, которые должны выглядеть по-разному на разных платформах. На основе шаблона проектирования Factory Method каждый компонент должен иметь выделенный ему фабричный класс, например если вы создаете приложение для Android, iOS и Интернета, каждый новый компонент также потребует добавить новый абстрактный класс и 3 дополнительных производных класса для реализации на каждой конкретной платформе.

Принимая во внимание упомянутые проблемы, шаблон проектирования Абстрактная фабрика является лучшим вариантом, чем фабричный метод, поскольку для каждой платформы требуется только одна фабрика, а семейство компонентов создается и используется вместе.

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

На диаграмме классов ниже показана реализация шаблона проектирования Абстрактная фабрика.

IWidgetsFactory - это абстрактный класс, который используется в качестве интерфейса для всех конкретных фабрик виджетов:

  • getTitle () - абстрактный метод, возвращающий заголовок фабрики. Используется в пользовательском интерфейсе;
  • createActivityIndicator () - абстрактный метод, который возвращает конкретную реализацию (компонент / виджет пользовательского интерфейса) индикатора активности (процесса), реализующего интерфейс IActivityIndicator;
  • createSlider () - абстрактный метод, который возвращает конкретную реализацию (компонент / виджет пользовательского интерфейса) ползунка, реализующего интерфейс ISlider;
  • createSwitch () - абстрактный метод, который возвращает конкретную реализацию (компонент / виджет пользовательского интерфейса) кнопки переключения, реализующей интерфейс ISwitch.

MaterialWidgetsFactory и CupertinoWidgetsFactory - это конкретные классы, реализующие класс IWidgetsFactory и его методы. MaterialWidgetsFactory создает компоненты стиля материала (виджеты), а CupertinoWidgetsFactory создает виджеты стиля Cupertino.

IActivityIndicator, ISlider и ISwitch - абстрактные классы, которые определяют метод render () для каждого компонента. Эти классы реализуются как виджетами - Материалом, так и виджетами Купертино.

AndroidActivityIndicator, AndroidSlider и AndroidSwitch - это конкретные реализации виджетов Material, реализующие метод render () соответствующих интерфейсов.

IosActivityIndicator, IosSlider и IosSwitch - это конкретные реализации виджетов Купертино, реализующие метод render () соответствующих интерфейсов.

AbstractFactoryExample содержит список фабрик, реализующих интерфейс IWidgetsFactory. После выбора конкретной фабрики примерный виджет использует свои методы для создания соответствующих виджетов / компонентов пользовательского интерфейса.

IWidgetsFactory

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

Фабрики виджетов

MaterialWidgetsFactory - конкретный фабричный класс, реализующий интерфейс IWidgetsFactory и его методы, создающие виджеты стиля материала.

CupertinoWidgetsFactory - конкретный фабричный класс, реализующий интерфейс IWidgetsFactory и его методы, создающие виджеты в стиле Купертино.

IActivityIndicator

Интерфейс, определяющий метод render () для визуализации компонента индикатора активности (виджета).

Виджеты индикатора активности

AndroidActivityIndicator - конкретная реализация компонента индикатора активности, возвращающего виджет стиля материала CircularProgressIndicator.

IosActivityIndicator - конкретная реализация компонента индикатора активности, возвращающего виджет в стиле Купертино CupertinoActivityIndicator.

ISlider

Интерфейс, определяющий метод render () для визуализации компонента слайдера (виджета).

Виджеты слайдера

AndroidSlider - конкретная реализация компонента слайдера, возвращающего виджет в стиле материала Slider.

IosSlider - конкретная реализация компонента слайдера, возвращающего виджет в стиле Купертино CupertinoSlider.

ISwitch

Интерфейс, определяющий метод render () для визуализации компонента переключателя (виджета).

Переключить виджеты

AndroidSwitch - конкретная реализация компонента кнопки переключения, возвращающего виджет в стиле материала Switch.

IosSwitch - конкретная реализация компонента кнопки переключения, возвращающего виджет в стиле Купертино CupertinoSwitch.

Пример

Прежде всего, подготавливается файл разметки, который предоставляется как описание шаблона:

AbstractFactoryExample содержит список объектов (фабрик) IWidgetsFactory. После выбора конкретной фабрики из списка соответствующие виджеты создаются с использованием фабричных методов и предоставляются пользовательскому интерфейсу.

Как вы можете видеть в методе build (), примерный виджет не заботится о выбранной конкретной фабрике, пока он реализует интерфейс IWidgetsFactory, методы которого возвращают компоненты, реализующие соответствующие общие интерфейсы для всех фабрик и предоставляющие методы render (), используемые в пользовательском интерфейсе. Кроме того, реализация конкретных виджетов инкапсулируется и определяется в отдельных классах виджетов, реализующих метод render (). Следовательно, логика пользовательского интерфейса не тесно связана с какой-либо фабрикой или классом компонентов, детали реализации которых могут быть изменены независимо, не влияя на реализацию самого пользовательского интерфейса.

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

Все изменения кода для шаблона проектирования Абстрактная фабрика и его пример реализации можно найти здесь.

Другие статьи из этой серии

Ваш вклад

👏 Нажмите кнопку хлопка ниже, чтобы выразить свою поддержку и побудить меня писать лучше!
💬 Оставьте отзыв на эту статью, поделившись своими мыслями, комментариями или пожеланиями относительно серии.
📢 Поделитесь этой статьей со своими друзья, коллеги в социальных сетях.
➕ Подписывайтесь на меня на Medium.
⭐ Пометьте репозиторий Github.