
Фабричный метод на C#
Фабричный метод — это порождающий паттерн проектирования, который решает проблему создания различных продуктов, без указания конкретных классов продуктов.
Фабричный метод задаёт метод, который следует использовать вместо вызова оператора new
для создания объектов-продуктов. Подклассы могут переопределить этот метод, чтобы изменять тип создаваемых продуктов.
Сложность:
Популярность:
Применимость: Паттерн можно часто встретить в любом C#-коде, где требуется гибкость при создании продуктов.
Признаки применения паттерна: Фабричный метод можно определить по создающим методам, которые возвращают объекты продуктов через абстрактные типы или интерфейсы. Это позволяет переопределять типы создаваемых продуктов в подклассах.
Концептуальный пример
Этот пример показывает структуру паттерна Фабричный метод, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
Program.cs: Пример структуры паттерна
using System; namespace RefactoringGuru.DesignPatterns.FactoryMethod.Conceptual { // Класс Создатель объявляет фабричный метод, который должен возвращать // объект класса Продукт. Подклассы Создателя обычно предоставляют // реализацию этого метода. abstract class Creator { // Обратите внимание, что Создатель может также обеспечить реализацию // фабричного метода по умолчанию. public abstract IProduct FactoryMethod(); // Также заметьте, что, несмотря на название, основная обязанность // Создателя не заключается в создании продуктов. Обычно он содержит // некоторую базовую бизнес-логику, которая основана на объектах // Продуктов, возвращаемых фабричным методом. Подклассы могут косвенно // изменять эту бизнес-логику, переопределяя фабричный метод и возвращая // из него другой тип продукта. public string SomeOperation() { // Вызываем фабричный метод, чтобы получить объект-продукт. var product = FactoryMethod(); // Далее, работаем с этим продуктом. var result = "Creator: The same creator's code has just worked with " + product.Operation(); return result; } } // Конкретные Создатели переопределяют фабричный метод для того, чтобы // изменить тип результирующего продукта. class ConcreteCreator1 : Creator { // Обратите внимание, что сигнатура метода по-прежнему использует тип // абстрактного продукта, хотя фактически из метода возвращается // конкретный продукт. Таким образом, Создатель может оставаться // независимым от конкретных классов продуктов. public override IProduct FactoryMethod() { return new ConcreteProduct1(); } } class ConcreteCreator2 : Creator { public override IProduct FactoryMethod() { return new ConcreteProduct2(); } } // Интерфейс Продукта объявляет операции, которые должны выполнять все // конкретные продукты. public interface IProduct { string Operation(); } // Конкретные Продукты предоставляют различные реализации интерфейса // Продукта. class ConcreteProduct1 : IProduct { public string Operation() { return "{Result of ConcreteProduct1}"; } } class ConcreteProduct2 : IProduct { public string Operation() { return "{Result of ConcreteProduct2}"; } } class Client { public void Main() { Console.WriteLine("App: Launched with the ConcreteCreator1."); ClientCode(new ConcreteCreator1()); Console.WriteLine(""); Console.WriteLine("App: Launched with the ConcreteCreator2."); ClientCode(new ConcreteCreator2()); } // Клиентский код работает с экземпляром конкретного создателя, хотя и // через его базовый интерфейс. Пока клиент продолжает работать с // создателем через базовый интерфейс, вы можете передать ему любой // подкласс создателя. public void ClientCode(Creator creator) { // ... Console.WriteLine("Client: I'm not aware of the creator's class," + "but it still works.\n" + creator.SomeOperation()); // ... } } class Program { static void Main(string[] args) { new Client().Main(); } } }
Output.txt: Результат выполнения
App: Launched with the ConcreteCreator1. Client: I'm not aware of the creator's class, but it still works. Creator: The same creator's code has just worked with {Result of ConcreteProduct1} App: Launched with the ConcreteCreator2. Client: I'm not aware of the creator's class, but it still works. Creator: The same creator's code has just worked with {Result of ConcreteProduct2}