Билеты ООП / 18. Паттерн Factory Method (фабричный метод)
.docx18. Паттерн Factory Method (фабричный метод)
1. Название: Factory Method
2. Задачи:
-
Система должна оставаться расширяемой путем добавления объектов новых типов. Непосредственное использование выражения new является нежелательным, так как в этом случае код создания объектов с указанием конкретных типов может получиться разбросанным по всему приложению. Тогда такие операции как добавление в систему объектов новых типов или замена объектов одного типа на другой будут затруднительными (подробнее в разделе Порождающие паттерны). Паттерн Factory Method позволяет системе оставаться независимой как от самого процесса порождения объектов, так и от их типов.
-
Заранее известно, когда нужно создавать объект, но неизвестен его тип.
3. Решение:
Для того, чтобы система оставалась независимой от различных типов объектов, паттерн Factory Method использует механизм полиморфизма - классы всех конечных типов наследуют от одного абстрактного базового класса, предназначенного для полиморфного использования. В этом базовом классе определяется единый интерфейс, через который пользователь будет оперировать объектами конечных типов.
Для обеспечения относительно простого добавления в систему новых типов паттерн Factory Method локализует создание объектов конкретных типов в специальном классе-фабрике. Методы этого класса, посредством которых создаются объекты конкретных классов, называются фабричными.
Интерфейс фабричных методов объявляется в независимом классе-фабрике, а их реализация определяется конкретными подклассами этого класса.
4. UML-диаграмма классов паттерна Factory Method. Классическая реализация
Product — собственно продукт. Предназначен для определения интерфейса объектов, создаваемых фабричным методом;
ConcreteProduct(Computer) — конкретные продукты, которые участвуют в схеме, и отвечают за реализацию абстрактного класса (интерфейса) Product.
Creator — создатель, и его название говорит само за себя. Данный объект предназначен для объявления фабричного метода, возвращающего объект типа Product.
ConcreteCreator — конкретный создатель. Здесь все очевидно: конкретная реализация создателя занимается тем, что возвращает конкретный продукт. В нашем примере конкретная реализация создателя — ComputerCreator.
Создатель доверяет своим подклассам реализацию подходящего конкретного продукта. В этом и заключается суть Factory Method.
5. Пример реализации Factory Method:
Класс Product — предназначен для определения интерфейса объектов, создаваемых фабричным методом. Это как бы базовая оболочка для продуктов. Продукт имеет цену и т.д.
-
abstract class Product
-
{
-
public abstract decimal PurchasePrice {get; set;}
-
public abstract decimal Price {get; set;}
-
public abstract string Description {get; set;}
-
}
Создаем класс, унаследованный от класса Product, который будет инкапсулировать логику конкретного продукта:
-
class Computer : Product
-
{
-
private decimal _purchase_price;
-
private decimal _price;
-
private string _description;
-
public Computer(string _description, decimal _purchase_price,
-
decimal _price)
-
{
-
this._description = _description;
-
this._purchase_price = _purchase_price;
-
this._price = _price;
-
}
-
public override string Description
-
{
-
get { return _description; }
-
set { _description = value; }
-
}
-
public override decimal Price
-
{
-
get { return _price; }
-
set { _price = value; }
-
}
-
public override decimal PurchasePrice
-
{
-
get { return _purchase_price; }
-
set { _purchase_price = value; }
-
}
-
}
Опишем абстрактный класс создателя, в котором есть фабричный метод.
-
abstract class Creator
-
{
-
public abstract Product FactoryMethod(string _description,
-
decimal _purchase_price, decimal _price);
-
}
Создаем конкретный класс создатель конкретного продукта (унаследован от Creator). В этом классе определяется метод для конструктора класса Computer (если конструкторов несколько, то для каждого конструктора определяется свой фабричный метод):
-
class ComputerCreator : Creator
-
{
-
public override Product FactoryMethod(string _description,
-
decimal _purchase_price, decimal _price)
-
{
-
return new Computer(_description,_purchase_price,_price);
-
}
-
}
Клиентский код:
-
static void Main(string[] args)
-
{
-
List<Product> productList = new List<Product>();
-
Creator[] creators = new Creator[1];
-
creators[0] = new ComputerCreator();
-
foreach (Creator cr in creators)
-
{
-
if (cr is ComputerCreator)
-
productList.Add(cr.FactoryMethod("Ноут бук", 600, 800));
-
}
-
foreach (Product pr in productList)
-
{
-
Console.WriteLine("Обьект класса {0};\n" +
-
"Описание: {1};\n" +
-
"Закупочная цена: {2};\n" +
-
"Цена продажы: {3};\n",
-
pr.GetType().Name,
-
pr.Description,
-
pr.PurchasePrice,
-
pr.Price);
-
}
-
}
Результат программы:
6. Плюсы и минусы данного паттерна:
Самый очевидный недостаток Factory Method — необходимость создавать наследника Creator всегда, когда планируется получить новый тип продукта (т.е. новый ConcreteProduct). И этого, увы, не избежать. Но подобная проблема присутствует во многих порождающих шаблонах. К достоинствам же следует отнести возможность создавать объекты более универсально, не ориентируясь на конкретные классы и оперируя общим интерфейсом.