Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Билеты ООП / 18. Паттерн Factory Method (фабричный метод)

.docx
Скачиваний:
71
Добавлен:
16.03.2016
Размер:
60.3 Кб
Скачать

18. Паттерн 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 — предназначен для определения интерфейса объектов, создаваемых фабричным методом. Это как бы базовая оболочка для продуктов. Продукт имеет цену и т.д. 

  1. abstract class Product  

  2. {  

  3.     public abstract decimal PurchasePrice {getset;}  

  4.     public abstract decimal Price {getset;}  

  5.     public abstract string Description  {getset;}  

  6. }  

Создаем класс, унаследованный от класса Product, который будет инкапсулировать логику конкретного продукта:

  1. class Computer : Product  

  2. {  

  3.     private decimal _purchase_price;  

  4.     private decimal _price;  

  5.     private string _description;  

  6.     public Computer(string _description, decimal _purchase_price,  

  7.                     decimal _price)  

  8.     {  

  9.         this._description = _description;  

  10.         this._purchase_price = _purchase_price;  

  11.         this._price = _price;  

  12.     }  

  13.     public override string Description  

  14.     {  

  15.         get { return _description; }  

  16.         set { _description = value; }  

  17.     }  

  18.     public override decimal Price  

  19.     {  

  20.         get { return _price; }  

  21.         set {   _price = value; }  

  22.     }  

  23.     public override decimal PurchasePrice  

  24.     {  

  25.         get { return _purchase_price; }  

  26.         set {   _purchase_price = value; }  

  27.     }  

  28. }  

Опишем абстрактный класс создателя, в котором есть фабричный метод.

  1. abstract class Creator  

  2. {  

  3.     public abstract Product FactoryMethod(string _description,  

  4.         decimal _purchase_price, decimal _price);  

  5. }  

Создаем конкретный класс создатель конкретного продукта (унаследован от Creator). В этом классе определяется метод для конструктора класса Computer (если конструкторов несколько, то для каждого конструктора определяется свой фабричный метод):

  1. class ComputerCreator : Creator  

  2. {  

  3.     public override Product FactoryMethod(string _description,  

  4.         decimal _purchase_price, decimal _price)  

  5.     {  

  6.         return new Computer(_description,_purchase_price,_price);  

  7.     }  

  8. }  

Клиентский код:

  1. static void Main(string[] args)  

  2. {  

  3.     List<Product> productList = new List<Product>(); 

  4.     Creator[] creators = new Creator[1];  

  5.     creators[0] = new ComputerCreator();

  6.     foreach (Creator cr in creators)  

  7.     {  

  8.         if (cr is ComputerCreator)  

  9.            productList.Add(cr.FactoryMethod("Ноут бук", 600, 800));  

  10.     }  

  11.     foreach (Product pr in productList)  

  12.     {  

  13.         Console.WriteLine("Обьект класса {0};\n" +  

  14.              "Описание: {1};\n" +  

  15.              "Закупочная цена: {2};\n" +  

  16.              "Цена продажы: {3};\n",  

  17.              pr.GetType().Name,  

  18.              pr.Description,  

  19.              pr.PurchasePrice,  

  20.              pr.Price);  

  21.     }  

  22. }  

Результат программы:

6. Плюсы и минусы данного паттерна:

Самый очевидный недостаток Factory Method — необходимость создавать наследника Creator всегда, когда планируется получить новый тип продукта (т.е. новый ConcreteProduct). И этого, увы, не избежать. Но подобная проблема присутствует во многих порождающих шаблонах. К достоинствам же следует отнести возможность создавать объекты более универсально, не ориентируясь на конкретные классы и оперируя общим интерфейсом.