Другое название: Kit (инструментарий).
Назначение: предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфицируя их конкретных классов.
Задача. Рассмотрим инструментальную программу для создания пользовательского интерфейса, поддерживающего разные стандарты внешнего облика, например обычные прямоугольные элементы управления (Rect) и округлые (Round). Чтобы приложение можно было перенести на другой стандарт, в нем не должен быть жестко закодирован внешний облик элементов управления. Если инстанцирование классов для конкретного внешнего облика разбросано по всему приложению, то изменить облик впоследствии будет нелегко.
Решение. Паттерн Абстрактная Фабрика предлагает решить эту проблему, определив абстрактный класс ControlsFactory, в котором объявлен интерфейс для создания всех основных видов элементов управления (англ. – controls): окна (window), кнопки (button) и т.д. Есть также абстрактные классы для каждого отдельного вида и конкретные подклассы, реализующие элементы управления с определенным внешним обликом. В интерфейсе ControlsFactory имеется операция, возвращающая новый объект для каждого вида элемента. Клиенты вызывают эти операции для получения экземпляров элементов управления, но при этом ничего не знают о том, какие именно классы используют. Стало быть, клиенты остаются независимыми от выбранного стандарта внешнего облика.

(Для простоты понимания опущены зависимости, отраженные в комментариях)
Для каждого стандарта внешнего облика существует определенный подкласс ControlsFactory. Каждый такой подкласс реализует операции, необходимые для создания соответствующего стандарту элемента управления. Например, операция CreateButton в классе RectControlsFactory инстанцирует и возвращает стандартную прямоугольную кнопку, тогда как соответствующая операция в классе RoundControlsFactory возвращает округлую кнопку. Клиенты создают элементы управления, пользуясь исключительно интерфейсами ControlsFactory, Window и Button, и им ничего не известно о классах, реализующих элементы управления для конкретного стандарта. Другими словами, клиенты должны лишь придерживаться интерфейса, определенного абстрактным, а не конкретным классом.
Класс ControlsFactory также устанавливает зависимости между конкретными классами элементов управления. Округлое окно должно использовать округлые кнопки, текстовые поля и т.д., и это ограничение поддерживается автоматически, как следствие использования класса RoundControlsFactory.
Общая структура решения.

(Для простоты понимания опущены зависимости, отраженные в комментариях)
AbstractFactory (ControlsFactory) – абстрактная фабрика: объявляет интерфейс для операций, создающих абстрактные объекты-продукты.
CocreteFactoryY (RectControlsFactory, RoundControlsFactory) – конкретная фабрика: реализует операции, создающие конкретные объекты-продукты типа Y.
AbstractProductX (Window, Button) – абстрактные продукты: объявляют интерфейс для типов объектов-продуктов.
ConcreteProductXY (RectWindow, RoundButton и др.) – конкретные продукты: определяют объекты-продукты, создаваемые конкретной фабрикой Y, реализуя интерфейс AbstractProductX.
Client – клиент: пользуется исключительно интерфейсами, которые объявлены в классах AbstractFactory и AbstractProductX.
Обычно во время выполнения создается единственный экземпляр класса ConcreteFactoryY. Эта конкретная фабрика создает объекты-продукты, имеющие вполне определенную реализацию. Для создания других видов объектов клиент должен воспользоваться другой конкретной фабрикой.
AbstractFactory передоверяет создание объектов-продуктов своим подклассам ConcreteFactoryY.
Применимость. Используйте паттерн Абстрактная Фабрика, когда:
- система не должна зависеть от того, как создаются, компонуются и представляются входящие в нее объекты;
- входящие в семейство взаимосвязанные объекты должны использоваться вместе, и вам необходимо обеспечить выполнение этого ограничения;
- система должна конфигурироваться одним из семейств составляющих ее объектов;
- вы хотите предоставить библиотеку объектов, раскрывая только их интерфейсы, но не реализацию.
Результаты. Паттерн Абстрактная Фабрика обладает следующими достоинствами и недостатками:
- изолирует конкретные классы. Помогает контролировать классы объектов, создаваемых приложением. Поскольку фабрика инкапсулирует ответственность за создание классов и сам процесс их создания, то она изолирует клиента от деталей реализации классов. Клиенты манипулируют экземплярами через их абстрактные интерфейсы. Имена изготавливаемых классов известны только конкретной фабрике, в коде клиента они не упоминаются;
- упрощает замену семейств продуктов. Класс конкретной фабрики появляется в приложении только один раз – при иистанцировании. Это облегчает замену используемой приложением конкретной фабрики. Приложение может изменить конфигурацию продуктов, просто подставив новую конкретную фабрику. Поскольку абстрактная фабрика создает все семейство продуктов, то и заменяется сразу все семейство. В нашем примере пользовательского интерфейса перейти от прямоугольных элементов управления к округлым можно, просто переключившись на продукты соответствующей фабрики и заново создав интерфейс;
- гарантирует сочетаемость продуктов. Если продукты некоторого семейства спроектированы для совместного использования, то важно, чтобы приложение в каждый момент времени работало только с продуктами единственного семейства. Класс AbstractFactory позволяет легко соблюсти это ограничение;
- трудно поддерживать новые виды продуктов. Расширение абстрактной фабрики для изготовления новых видов продуктов – непростая задача. Интерфейс AbstractFactory фиксирует набор продуктов, которые можно создать. Для поддержки новых продуктов необходимо расширить интерфейс фабрики, то есть изменить класс AbstractFactory и все его подклассы.
Особенности реализации. Вот некоторые полезные приемы реализации паттерна Абстрактная Фабрика.
- фабрики как объекты существующие в единственном экземпляре: как правило, приложению нужен только один экземпляр класса ConcreteFactory на каждое семейство продуктов. Поэтому для реализации лучше всего применить паттерн Одиночка;
- создание продуктов: класс AbstractFactory объявляет только интерфейс для создания продуктов. Фактическое их создание – дело подклассов ConcreteFactory. Чаще всего для этой цели определяется фабричный метод для каждого продукта (паттерн Фабричный Метод). Конкретная фабрика специфицирует свои продукты путем замещения фабричного метода для каждого из них. Хотя такая реализация проста, она требует создавать новый подкласс конкретной фабрики для каждого семейства продуктов, даже если они почти ничем не отличаются;
- если семейств продуктов может быть много, то конкретную фабрику удастся реализовать с помощью паттерна Прототип. В этом случае она инициализируется экземпляром-прототипом каждого продукта в семействе и создает новый продукт путем клонирования этого прототипа. Подход на основе прототипов устраняет необходимость создавать новый класс конкретной фабрики для каждого нового семейства продуктов;
- определение расширяемых фабрик: класс AbstractFactory обычно определяет разные операции для каждого вида изготавливаемых продуктов. Виды продуктов кодируются в сигнатуре операции. Для добавления нового вида продуктов нужно изменить интерфейс класса AbstractFactory и всех зависящих от него классов. Более гибкий, но не такой безопасный способ – добавить параметр к операциям, создающим объекты. Данный параметр определяет вид создаваемого объекта. Это может быть любой идентификатор, однозначно описывающий вид продукта. При таком подходе классу AbstractFactory нужна только одна операция CreateProduct с параметром, указывающим тип создаваемого объекта. Такой вариант удобно использовать в динамически типизированных языках типа Smalltalk, нежели в статически типизированных, каким является, например, C++. Воспользоваться данным подходом в C++ можно только, если у всех объектов имеется общий абстрактный базовый класс или если объекты-продукты могут быть безопасно приведены к корректному типу клиентом, который их запросил. Но даже если приведение типов не нужно, остается принципиальная проблема: все продукты возвращаются клиенту одним и тем же абстрактным интерфейсом с уже определенным типом возвращаемого значения. Клиент не может ни различить классы продуктов, ни сделать какие-нибудь предположения о них. Если клиенту нужно выполнить операцию, зависящую от подкласса, то она будет недоступна через абстрактный интерфейс. Хотя клиент может выполнить динамическое приведение типа, это однозначно небезопасно. Здесь мы имеем классический пример компромисса между высокой степенью гибкости и расширяемостью интерфейса.
Родственные паттерны.
Классы AbstractFactory почти всегда используют Фабричные Методы, но могут быть реализованы и с помощью паттерна Прототип.
Конкретная фабрика часто описывается паттерном Одиночка.