Abstract Factory (Абстрактная фабрика)¶
Категория: порождающий паттерн.
Проблема¶
Приложению нужно создавать не один объект, а согласованное семейство связанных объектов - например, набор UI-контролов одной темы (кнопка, чекбокс, поле ввода) или набор компонентов под конкретную СУБД (соединение, команда, адаптер). При этом важно гарантировать, что объекты из разных семейств никогда не будут случайно смешаны (светлая кнопка с тёмным чекбоксом, MySQL-соединение с PostgreSQL-командой).
Если создавать каждый объект по отдельности через new в клиентском коде, ничто не мешает случайно смешать компоненты разных семейств, а сам клиентский код жёстко привязывается к конкретным классам.
Решение¶
- Для каждого вида продукта в семействе выделяется абстракция (
IButton,ICheckbox). - Вводится интерфейс абстрактной фабрики с одним методом создания на каждый вид продукта (
CreateButton(),CreateCheckbox()). - На каждое семейство пишется своя конкретная фабрика (
LightUiFactory,DarkUiFactory), которая создаёт продукты именно этого семейства. - Клиентский код получает одну конкретную фабрику (обычно через DI или конфигурацию) и создаёт через неё все нужные объекты - гарантированно из одного семейства.
Структура¶
AbstractProductA,AbstractProductB- абстракции продуктов.ConcreteProductA1/A2,ConcreteProductB1/B2- реализации продуктов для разных семейств.IAbstractFactory- интерфейс с методом на каждый вид продукта.ConcreteFactory1/2- конкретные фабрики, создающие продукты одного семейства.Client- работает только с абстракциямиIAbstractFactory,AbstractProductA/B.
Когда применять¶
- В системе есть несколько семейств взаимосвязанных продуктов, и важно гарантировать, что используется ровно одно семейство за раз.
- Нужно легко переключать целое семейство реализаций (тема оформления, СУБД, облачный провайдер) в одном месте, не меняя клиентский код.
Плюсы¶
- Гарантирует совместимость продуктов внутри одного семейства.
- Изолирует клиентский код от конкретных классов продуктов.
- Новое семейство добавляется новой фабрикой, без изменения существующего кода (открытость/закрытость).
Минусы¶
- Добавление нового вида продукта (например,
IRadioButtonв дополнение к кнопке и чекбоксу) требует изменения интерфейса фабрики и всех её реализаций - это нарушает открытость/закрытость в другом направлении. - Больше кода и абстракций, чем при прямом создании объектов - оправдано только при реальном наличии нескольких семейств.
Отличие от Factory Method¶
Abstract Factory обычно реализуется через несколько Factory Method - каждый метод фабрики (CreateButton, CreateCheckbox) сам по себе является фабричным методом. Разница в масштабе: Factory Method - это точка расширения в одном классе для одного продукта, Abstract Factory - самостоятельный объект, отвечающий за целое семейство продуктов.
Пример в .NET Framework / BCL¶
System.Data.Common.DbProviderFactory- абстрактная фабрика для ADO.NET: конкретные реализации (SqlClientFactory,NpgsqlFactory) создают согласованное семействоDbConnection,DbCommand,DbDataAdapterдля конкретной СУБД.- Фабрики контролов в кросс-платформенных UI-фреймворках, где один "движок рендеринга" должен создавать визуально согласованный набор элементов управления.
Пример реализации на C#¶
Открыть AbstractFactory.cs отдельно
Скачать AbstractFactory.cs