Factory Method (Фабричный метод)¶
Категория: порождающий паттерн.
Проблема¶
Базовый класс реализует общий алгоритм, но одна из его частей - создание конкретного объекта - должна отличаться в зависимости от контекста, и заранее (на этапе написания базового класса) неизвестно, какой именно конкретный тип понадобится.
Если "зашить" в базовый класс прямое создание конкретного продукта (new ConcreteProduct()), базовый класс окажется жёстко привязан к этой конкретной реализации и не сможет быть переиспользован для других вариантов продукта без изменения своего кода.
Решение¶
- Выделяется общий интерфейс (или базовый класс) для создаваемых объектов - продукт.
- В базовом классе-создателе создание продукта выносится в отдельный виртуальный/абстрактный метод ("фабричный метод").
- Подклассы-создатели переопределяют этот метод, возвращая нужную им конкретную реализацию продукта.
- Остальной код базового класса (алгоритм, использующий продукт) остаётся общим и не дублируется.
Ключевая идея: создание объекта откладывается до подкласса, но сам алгоритм использования этого объекта остаётся в одном месте.
Структура¶
Product- интерфейс создаваемого объекта.ConcreteProduct- конкретные реализации продукта.Creator- абстрактный класс с фабричным методомCreateProduct()и общей бизнес-логикой, которая этот метод использует.ConcreteCreator- переопределяет фабричный метод, возвращая конкретный продукт.
Когда применять¶
- Класс не может заранее знать, объекты какого именно подкласса он должен создать.
- Логика, использующая объект, единая, а вот создание объекта должно различаться в разных сценариях/подклассах.
- Хочется дать пользователям библиотеки возможность расширять набор создаваемых типов, не трогая код самой библиотеки (переопределив фабричный метод в своём подклассе).
Плюсы¶
- Убирает дублирование общей логики между вариантами создателя.
- Соблюдает принцип открытости/закрытости: новый вариант продукта добавляется новым подклассом, без изменения существующего кода.
Минусы¶
- Требует создавать подкласс
Creatorна каждый новый вид продукта - если вариантов много и они добавляются часто, иерархия классов быстро разрастается. - Для простых случаев (когда общей логики вокруг создания почти нет) это избыточная абстракция - обычная функция-фабрика или
Func<T>решают задачу проще.
Отличие от Abstract Factory¶
Factory Method - это один метод, переопределяемый в подклассе, для создания одного вида продукта. Abstract Factory - это отдельный объект-фабрика с несколькими методами, создающий семейство согласованных продуктов. Abstract Factory нередко реализуют, используя внутри несколько Factory Method.
Пример в .NET Framework / BCL¶
Stream.CreateWaitHandle()(устаревший, но исторически показательный пример).- Многие
*Provider/*Factoryклассы в ADO.NET:DbProviderFactory.CreateConnection(),CreateCommand()- конкретная фабрика (SqlClientFactory,NpgsqlFactory) решает, объекты каких конкретных классов вернуть. HttpMessageHandlerFactoryвнутриIHttpClientFactory.