1 22.8K ru

Порождающие паттерны: «Фабричный метод» (Factory Method)

Categories: 💻 Programming

Назначение: определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанцировать. Фабричный метод позволяет классу делегировать инстанцирование подклассам.

Когда следует использовать фабричный метод

  • Когда заранее неизвестно, объекты каких типов необходимо создавать;
  • Когда система должна быть независимой от процесса создания новых объектов и расширяемой: в нее можно легко вводить новые классы, объекты которых система должна создавать;
  • Когда создание новых объектов необходимо делегировать из базового класса классам наследникам;

Схема примера использования паттерна "Фабричный метод"  из реальной жизни:

Схема примера использования паттерна "Фабричный метод"  из реальной жизни

UML схема паттерна фабричный метод

UML схема паттерна фабричный метод

Реализация шаблона "фабричный метод" на C#

using System;
 
namespace DoFactory.GangOfFour.Factory.Structural
{
  class MainApp
  {
 
    static void Main()
    {
      // An array of creators
      Creator[] creators = new Creator[2];
 
      creators[0] = new ConcreteCreatorA();
      creators[1] = new ConcreteCreatorB();
 
      // Iterate over creators and create products
      foreach (Creator creator in creators)
      {
        Product product = creator.FactoryMethod();
        Console.WriteLine("Created {0}",
          product.GetType().Name);
      }
 
      // Wait for user
      Console.ReadKey();
    }
  }

  abstract class Product
  {
  }

  class ConcreteProductA : Product
  {
  }
 
  class ConcreteProductB : Product
  {
  }
 
  abstract class Creator
  {
    public abstract Product FactoryMethod();
  }

  class ConcreteCreatorA : Creator
  {
    public override Product FactoryMethod()
    {
      return new ConcreteProductA();
    }
  }
 
  class ConcreteCreatorB : Creator
  {
    public override Product FactoryMethod()
    {
      return new ConcreteProductB();
    }
  }
}

Output

Created ConcreteProductA
Created ConcreteProductB

 Обсуждение паттерна «Фабричный метод»

У каждой реализации фабричного метода есть свои особенности

  1. Классический фабричный метод является частным случаем шаблонного метода. Это значит, что фабричный метод привязан к текущей иерархии типов и не может быть использован повторно в другом контексте.
  2. Полиморфный фабричный метод является стратегией создания экземпляров некоторого семейства типов, что позволяет использовать одну фабрику в разных контекстах. Тип создаваемого объекта определяется типом фабрики и обычно не зависит от аргументов фабричного метода.
  3. Статический фабричный метод является самой простой формой фабричного метода. Статический метод создания позволяет обойти ограничения конструк- торов. Например, тип создаваемого объекта может зависеть от аргументов ме- тода, экземпляр может возвращаться из кэша, а не создаваться заново или же фабричный метод может быть асинхронным.

Использование Func в качестве фабрики

В некоторых случаях Func может использоваться в качестве полноценной фабрики и передаваться классу извне его клиентами. Данный вариант фабрики является допустимым во внутреннем (internal) коде и только для функций с небольшим количеством аргументов. Понять, что делает Func, довольно просто, но разобраться в назначении Func<int, string, int, ValidationResult> factory без контекста будет практически невозможно.Читаемость кода очень важна, поэтому именованная фабрика является предпочтительным вариантом.

Конструктор vs. фабричный метод

В объектно-ориентированных языках программирования конструктор отвечает за корректную инициализацию создаваемого объекта. В большинстве случаев они прекрасно справляются со своей задачей, но иногда лучше воспользоваться статическим фабричным методом.

Именованные конструкторы.

В языке C# имя конструктора совпадает с именем класса, что делает невозможным использование двух конструкторов с одним набором и типом параметров. Хорошим примером такого ограничения является структура Timespan, которая представляет собой интервал времени. Очень удобно создавать интервал времени по количеству секунд, минут, часов и дней, но сделать несколько конструкторов, каждый из которых принимает один параметр типа double, невозможно. Для этого структура Timespan содержит набор фабричных методов (пример ниже)

public struct Timespan
{
 public Timespan(double ticks) { ... }
 public static Timespan FromMilliseoncds(double value) {...}
 public static Timespan FromSeconds(double value) {...}
 public static Timespan FromMinutes(double value) {...}
}

Тяжеловесный процесс создания

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

Примеры в .NET Framework

В .NET Framework применяется огромное количество фабрик.

  1. Классический фабричный метод: Stream.CreateWaitHandle, SecurityAttribute.CreatePermission, ChannelFactory.CreateChannel, XmlNode.CreateNavigator.
  2. Полиморфная фабрика: IControllerFactory в ASP.NET MVC, IHttpHandlerFactory в ASP.NET, ServiceHostFactory и IChannelFactory в WCF, IQueryProvider в LINQ.
  3. Неполиморфная фабрика: TaskFactory в TPL.
  4. Обобщенная статическая фабрика: Activator.CreateInstance, Array.CreateInstance, StringComparer.Create.
  5. Сокрытие наследников: RandomNumberGenerator.Create, WebRequest.Create, BufferManager.CreateBufferManager, Message.CreateMessage, MessageFault.CreateFault
  6. Фасадные фабричные методы: File.Create, File.CreateText.
  7. Именованные конструкторы: Timespan.FromSecond, Timespan.FromMilliseconds, GCHandle.FromIntPtr, Color.FromArgb.

Comments:

Please log in to be able add comments.
👍