- •А.А. Волосевич
- •3. Шаблоны и архитектура программ
- •3.1. Модульное тестирование
- •3.2. Шаблоны проектирования
- •3.3. Структурные шаблоны: Декоратор, Заместитель, мост Декоратор (Decorator)
- •Заместитель (Proxy)
- •Мост (Bridge)
- •3.4. Структурные шаблоны: компоновщик и приспособленец Компоновщик (Composite)
- •Приспособленец (Flyweight)
- •3.5. Структурные шаблоны: адаптер и фасад Адаптер (Adapter)
- •Фасад (Façade)
- •3.6. Порождающие шаблоны: прототип, фабричный метод, одиночка Прототип (Prototype)
- •Фабричный метод (Factory method)
- •Одиночка (Singleton)
- •3.7. Порождающие шаблоны: абстрактная фабрика и строитель Абстрактная фабрика (Abstract factory)
- •Строитель (Builder)
- •3.8. Шаблоны поведения: стратегия, состояние, шаблонный метод Стратегия (Strategy)
- •Состояние (State)
- •Шаблонный метод (Template method)
- •3.9. Шаблоны поведения: цепочка обязанностей и команда Цепочка обязанностей (Chain of responsibility)
- •Команда (Command)
- •3.10. Шаблоны поведения: итератор, посредник, наблюдатель Итератор (Iterator)
- •Посредник (Mediator)
- •Наблюдатель (Observer)
- •3.11. Шаблоны поведения: посетитель, интерпретатор, хранитель Посетитель (Visitor)
- •Интерпретатор (Interpreter)
- •Хранитель (Memento)
- •3.12. Некоторые неклассические шаблоны проектирования
- •Неизменный объект (Immutable object)
- •Пул объектов (Object pool)
- •Отложенная инициализация (Lazy initialization)
- •Нулевой объект (Null object)
- •3.13. Антипаттерны
- •3.14. Архитектура прогРаммного Обеспечения
- •«Клиент-сервер»
- •Архитектура, основанная на использовании компонентов
- •Многоуровневая архитектура
- •Шина сообщений
- •Выделенное представление
- •Объектно-ориентированная архитектура
- •Архитектура, ориентированная на сервисы
3.6. Порождающие шаблоны: прототип, фабричный метод, одиночка Прототип (Prototype)
Шаблон Прототип позволяет создавать специальные объекты, ничего не знаю об их классе или деталях создания. Механизм можно описать так: клиенту, инициирующему создание объектов, предоставляются объекты-прототипы. Затем целевые объекты создаются путем клонирования этих объектов-прототипов.
Объект обычно создаётся путем вызова конструктора. Если же используется шаблон Прототип, то клиент знает только об интерфейсе IPrototype, реализующем операции клонирования объекта. Реальный класс объекта клиенту не известен. Прототипы для клонирования могут использоваться произвольное количество раз, сами он при операции клонирования меняться не должны. Хотя существуют различные варианты дизайна данного шаблона, наиболее гибким является вариант с менеджером прототипов, содержащим индексированный список доступных прототипов.
Рис. 10. Дизайн шаблона Прототип.
При реализации шаблона Прототип для платформы .NET следует учитывать, что пользовательские объекты могут быть ссылочными типами, а, значит, требовать дополнительных усилий по получению полной копии. Ниже приводится пример кода, в котором для полного копирования используются возможности сериализации.
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
// Тип T должен быть сериализуемым!
public abstract class Prototype<T>
{
// Поверхностное копирование
public T Clone()
{
return (T)MemberwiseClone();
}
// Глубокое копирование
public T DeepCopy()
{
var stream = new MemoryStream();
var formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Seek(0, SeekOrigin.Begin);
var copy = (T)formatter.Deserialize(stream);
stream.Close();
return copy;
}
}
Фабричный метод (Factory method)
Фабричный метод занимается созданием объектов. Каждый такой объект принадлежит некому классу, однако все классы либо имеют общего предка, либо реализуют общий интерфейс. Фабричный метод сам решает, какой конкретный класс нужно использовать для создания очередного объекта. Решение принимается либо на основе информации, предоставленной клиентом, либо на основе внутреннего состояния метода.
Для иллюстрации шаблона Фабричный метод представим магазин, торгующий определенным видом фруктов. Магазин (выступающий в роли клиента) работает с поставщиком (фабричный метод), который в зависимости от времени года импортирует фрукты (объекты) из разных стран (разные классы объектов). Как видим, детали операций импорта от клиента скрыты и независимы.
Рис. 11. UML-диаграмма шаблона Фабричный метод.
Далее приведён код, использующий шаблон Фабричный метод и соответствующий описанному выше гипотетическому примеру.
using System;
public interface IProduct
{
string ShipFrom();
}
public class ProductFromAfrica : IProduct
{
public String ShipFrom()
{
return "from South Africa";
}
}
public class ProductFromSpain : IProduct
{
public String ShipFrom()
{
return "from Spain";
}
}
public class DefaultProduct : IProduct
{
public String ShipFrom()
{
return "not available";
}
}
public class Creator
{
public IProduct FactoryMethod(int month)
{
if (month >= 4 && month <= 11)
{
return new ProductFromAfrica();
}
if (month == 12 || month == 2 || month == 1)
{
return new ProductFromSpain();
}
return new DefaultProduct();
}
}
public class FactoryMethodExample
{
private static void Main()
{
var c = new Creator();
IProduct product;
for (var i = 1; i <= 12; i++)
{
product = c.FactoryMethod(i);
Console.WriteLine("Avocados " + product.ShipFrom());
}
}
}