Фабрика (шаблон проектирования) Википедия

Абстрактная фабрика (Abstract Factory)

Последнее обновление: 31.10.2015

Паттерн «Абстрактная фабрика» (Abstract Factory) предоставляет интерфейс для создания семейств взаимосвязанных объектов с определенными интерфейсами без указания конкретных типов данных объектов.

Когда использовать абстрактную фабрику

  • Когда система не должна зависеть от способа создания и компоновки новых объектов

  • Когда создаваемые объекты должны использоваться вместе и являются взаимосвязанными

С помощью UML абстрактную фабрику можно представить следующим образом:

Формальное определение паттерна на языке C# может выглядеть следующим образом:

abstract class AbstractFactory { public abstract AbstractProductA CreateProductA(); public abstract AbstractProductB CreateProductB(); } class ConcreteFactory1: AbstractFactory { public override AbstractProductA CreateProductA() { return new ProductA1(); } public override AbstractProductB CreateProductB() { return new ProductB1(); } } class ConcreteFactory2: AbstractFactory { public override AbstractProductA CreateProductA() { return new ProductA2(); } public override AbstractProductB CreateProductB() { return new ProductB2(); } } abstract class AbstractProductA {} abstract class AbstractProductB {} class ProductA1: AbstractProductA {} class ProductB1: AbstractProductB {} class ProductA2: AbstractProductA {} class ProductB2: AbstractProductB {} class Client { private AbstractProductA abstractProductA; private AbstractProductB abstractProductB; public Client(AbstractFactory factory) { abstractProductB = factory.CreateProductB(); abstractProductA = factory.CreateProductA(); } public void Run() { } }

Паттерн определяет следующих участников:

  • Абстрактные классы AbstractProductA и AbstractProductB определяют интерфейс для классов, объекты которых будут создаваться в программе.

  • Конкретные классы ProductA1 / ProductA2 и ProductB1 / ProductB2 представляют конкретную реализацию абстрактных классов

  • Абстрактный класс фабрики AbstractFactory определяет методы для создания объектов. Причем методы возвращают абстрактные продукты, а не их конкретные реализации.

  • Конкретные классы фабрик ConcreteFactory1 и ConcreteFactory2 реализуют абстрактные методы базового класса и непосредственно определяют какие конкретные продукты использовать

  • Класс клиента Client использует класс фабрики для создания объектов. При этом он использует исключительно абстрактный класс фабрики AbstractFactory и абстрактные классы продуктов AbstractProductA и AbstractProductB и никак не зависит от их конкретных реализаций

Посмотрим, как мы можем применить паттерн. Например, мы делаем игру, где пользователь должен управлять некими супергероями, при этом каждый супергерой имеет определенное оружие и определенную модель передвижения.

Antananarivo Фото со стоков и изображения

Различные супергерои могут определяться комплексом признаков. Например, эльф может летать и должен стрелять из арбалета, другой супергерой должен бегать и управлять мечом. Таким образом, получается, что сущность оружия и модель передвижения являются взаимосвязанными и используются в комплексе. То есть имеется один из доводов в пользу использования абстрактной фабрики.

И кроме того, наша задача при проектировании игры абстрагировать создание супергероев от самого класса супергероя, чтобы создать более гибкую архитектуру. И для этого применим абстрактную фабрику:

class Program { static void Main(string[] args) { Hero elf = new Hero(new ElfFactory()); elf.Hit(); elf.Run(); Hero voin = new Hero(new VoinFactory()); voin.Hit(); voin.Run(); Console.ReadLine(); } } //абстрактный класс — оружие abstract class Weapon { public abstract void Hit(); } // абстрактный класс движение abstract class Movement { public abstract void Move(); } // класс арбалет class Arbalet : Weapon { public override void Hit() { Console.WriteLine(«Стреляем из арбалета»); } } // класс меч class Sword : Weapon { public override void Hit() { Console.WriteLine(«Бьем мечом»); } } // движение полета class FlyMovement : Movement { public override void Move() { Console.WriteLine(«Летим»); } } // движение — бег class RunMovement : Movement { public override void Move() { Console.WriteLine(«Бежим»); } } // класс абстрактной фабрики abstract class HeroFactory { public abstract Movement CreateMovement(); public abstract Weapon CreateWeapon(); } // Фабрика создания летящего героя с арбалетом class ElfFactory : HeroFactory { public override Movement CreateMovement() { return new FlyMovement(); } public override Weapon CreateWeapon() { return new Arbalet(); } } // Фабрика создания бегущего героя с мечом class VoinFactory : HeroFactory { public override Movement CreateMovement() { return new RunMovement(); } public override Weapon CreateWeapon() { return new Sword(); } } // клиент — сам супергерой class Hero { private Weapon weapon; private Movement movement; public Hero(HeroFactory factory) { weapon = factory.CreateWeapon(); movement = factory.CreateMovement(); } public void Run() { movement.Move(); } public void Hit() { weapon.Hit(); } }

Таким образом, создание супергероя абстрагируется от самого класса супергероя.

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

НазадСодержаниеВперед

Паттерн Factory Method — Фабрика

2005-12-30 ООП и паттерны проектирования

Factory Method — это паттерн создания объектов (creational pattern). Данный шаблон проектирования предоставляет интерфейс для создания экземпляров некоторого класса.

antananarivo

В момент создания наследники могут определить, какой класс инстанциировать.

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

Паттерн проектирования Factory встречается очень часто. Рассмотрим небольшой пример на Java.

Вступление: Требования к разного рода програмным продуктам постоянно растут. Отчеты по выполнению операций приложения должны формироваться в разном виде: XML, HTML, текст и т.д. Это как раз тот случай, когда удобно использовать паттерн Factory.

Решение: Класс AbstractWriter будет представлять абстракцию для записи в некоторый контекст (будь то XML-документ или текстовый файл).

public abstract class AbstractWriter { public abstract void write(Object context); }

У этого класса может быть любое кол-во наследников. Рассмотрим подклассы ConcreteFileWriter и ConcreteXmlWriter для записи в текстовый файл и DOM документ соответственно:

public class ConcreteFileWriter extends AbstractWriter { public void write (Object context) { // method body } } public class ConcreteXmlWriter extends AbstractWriter { public void write (Object context) { // method body } }

Для создания нужного нам объекта можно написать следующую Фабрику:

import java.io.File; import org.w3c.dom.Document; public class FactoryMethod { public AbstractWriter getWriter(Object object) { AbstractWriter writer = null; if (object instanceof File) { writer = new ConcreteFileWriter(); } else if (object instanceof Document) { writer = new ConcreteXmlWriter(); } return writer; } }

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

Используйте паттерн Factory в следующих случаях:

  • класс не имеет информации о том, какой тип объекта он должен создать;
  • класс передает ответственность по созданию объектов наследникам;
  • необходимо создать объект в зависимости от входящих данных.

В одной из последующих статей по проектированию мы рассмотрим паттерн Abstract Factory.

А пока что я с удовольствием выслушаю ваши вопросы, замечания и комментарии.

Порождающие паттерны

Фабричный метод (Factory Method)

Последнее обновление: 31.10.2015

Фабричный метод (Factory Method) — это паттерн, который определяет интерфейс для создания объектов некоторого класса, но непосредственное решение о том, объект какого класса создавать происходит в подклассах. То есть паттерн предполагает, что базовый класс делегирует создание объектов классам-наследникам.

Когда надо применять паттерн

  • Когда заранее неизвестно, объекты каких типов необходимо создавать

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

  • Когда создание новых объектов необходимо делегировать из базового класса классам наследникам

На языке UML паттерн можно описать следующим образом:

Формальное определение паттерна на языке C# может выглядеть следующим образом:

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(); } }

Участники

  • Абстрактный класс Product определяет интерфейс класса, объекты которого надо создавать.

  • Конкретные классы ConcreteProductA и ConcreteProductB представляют реализацию класса Product. Таких классов может быть множество

  • Абстрактный класс Creator определяет абстрактный фабричный метод , который возвращает объект Product.

  • Конкретные классы ConcreteCreatorA и ConcreteCreatorB — наследники класса Creator, определяющие свою реализацию метода . Причем метод каждого отдельного класса-создателя возвращает определенный конкретный тип продукта. Для каждого конкретного класса продукта определяется свой конкретный класс создателя.

    Таким образом, класс Creator делегирует создание объекта Product своим наследникам. А классы ConcreteCreatorA и ConcreteCreatorB могут самостоятельно выбирать какой конкретный тип продукта им создавать.

Теперь рассмотрим на реальном примере. Допустим, мы создаем программу для сферы строительства. Возможно, вначале мы захотим построить многоэтажный панельный дом. И для этого выбирается соответствующий подрядчик, который возводит каменные дома.

Авиабилеты Найроби — Антананариву

Затем нам захочется построить деревянный дом и для этого также надо будет выбрать нужного подрядчика:

class Program { static void Main(string[] args) { Developer dev = new PanelDeveloper(«ООО КирпичСтрой»); House house2 = dev.Create(); dev = new WoodDeveloper(«Частный застройщик»); House house = dev.Create(); Console.ReadLine(); } } // абстрактный класс строительной компании abstract class Developer { public string Name { get; set; } public Developer (string n) { Name = n; } // фабричный метод abstract public House Create(); } // строит панельные дома class PanelDeveloper : Developer { public PanelDeveloper(string n) : base(n) { } public override House Create() { return new PanelHouse(); } } // строит деревянные дома class WoodDeveloper : Developer { public WoodDeveloper(string n) : base(n) { } public override House Create() { return new WoodHouse(); } } abstract class House { } class PanelHouse : House { public PanelHouse() { Console.WriteLine(«Панельный дом построен»); } } class WoodHouse : House { public WoodHouse() { Console.WriteLine(«Деревянный дом построен»); } }

В качестве абстрактного класса Product здесь выступает класс House. Его две конкретные реализации — PanelHouse и WoodHouse представляют типы домов, которые будут строить подрядчики. В качестве абстрактного класса создателя выступает Developer, определяющий абстрактный метод . Этот метод реализуется в классах-наследниках WoodDeveloper и PanelDeveloper. И если в будущем нам потребуется построить дома какого-то другого типа, например, кирпичные, то мы можем с легкостью создать новый класс кирпичных домов, унаследованный от House, и определить класс соответствующего подрядчика. Таким образом, система получится легко расширяемой. Правда, недостатки паттерна тоже очевидны — для каждого нового продукта необходимо создавать свой класс создателя.

НазадСодержаниеВперед

Добавить комментарий

Закрыть меню