
- •1. Базовые сведения о шаблонах проектирования
- •2. Структурные шаблоны
- •2.1. Адаптер (Adapter)
- •2.2. Декоратор (Decorator)
- •2.3. Заместитель (Proxy)
- •2.4. Компоновщик (Composite)
- •2.5. Мост (Bridge)
- •2.6. Приспособленец (Flyweight)
- •2.7. Фасад (Facade)
- •3. Порождающие шаблоны
- •3.1. Абстрактная фабрика (Abstract factory)
- •3.2. Одиночка (Singleton)
- •3.3. Отложенная инициализация (Lazy initialization)
- •3.4. Прототип (Prototype)
- •3.5. Пул объектов (Object pool)
- •3.6. Строитель (Builder)
- •3.7. Фабричный метод (Factory method)
- •4. Шаблоны поведения
- •4.1. Итератор (Iterator)
- •4.2. Команда (Command)
- •4.3. Наблюдатель (Observer)
- •4.4. Нулевой объект (Null object)
- •4.5. Посетитель (Visitor)
- •4.6. Посредник (Mediator)
- •4.7. Состояние (State)
- •4.8. Стратегия (Strategy)
- •4.9. Цепочка обязанностей (Chain of responsibility)
- •4.10. Шаблонный метод (Template method)
- •5. Антипаттерны
- •Литература

Все готово к применению компонентов и их декораторов. Вначалесоздадим исходный компонент, а потом дополним его возможности, используя оба декоратора. Обратите внимание на то, что несколько декораторов могут независимо применяться к одному и тому же объекту, а также на то, что декоратор может декорировать объект, который уже декорирован.
// обыкновенный элемент
IElement element = new Element {Text = "Demo"}; element.Draw();
// декорирование отступом
IElement ei = new ElementWithIdent(element) {Ident = 4}; ei.Draw();
// дополнительное декорирование скобками
IElement eb = new ElementWithBrackets(ei); eb.Draw();
2.3. Заместитель (Proxy)
Шаблон Заместитель позволяет контролировать доступ к заданному объекту, перехватывая все вызовы к этому объекту и прозрачно замещая его. Ни интерфейс, ни функциональность замещённого объекта с точки зрения клиента не меняются. Данный шаблон часто используется, если необходимо упростить или оптимизировать взаимодействие с объектом, скрывая несущественные для конкретной задачи подробности реализации.
На рис 3. показан дизайн шаблона Заместитель. И заместитель Proxy, и класс замещаемого объекта Subject реализуют общий интерфейс ISubject. Заместитель может агрегировать замещаемый объект или порождать локальныеэкземпляры этого объекта при необходимости. Как правило, клиент не имеет прямого доступа к замещаемому объекту.
Client |
<<interface>> |
|
ISubject |
|
+Request() |
Proxy |
Subject |
+Request() |
+Request() |
Рис. 3. Дизайн шаблона Заместитель. Перечислим некоторые разновидности шаблона Заместитель:
9
– Удалённый заместитель (remote proxy) обеспечивает связь с замещаемым объектом, который находится в другом адресном пространстве или наудалённой машине;
–Виртуальный заместитель (virtual proxy) реализует создание замещаемого объекта только тогда, когда он действительно необходим;
–Защищающий заместитель (protection proxy) проверяет, имеет ли вызы-
вающий объект необходимые для выполнения запроса права.
Рассмотрим примера реализации виртуального заместителя для оптимизации работы с большими изображениями.
public interface IImage
{
void Display();
}
public class RealImage : IImage
{
private readonly string _filename;
public RealImage(string filename)
{
_filename = filename; LoadImageFromDisk();
}
public void Display()
{
Console.WriteLine("Displaying " + _filename);
}
private void LoadImageFromDisk()
{
Console.WriteLine("Loading " + _filename);
}
}
public class ProxyImage : IImage
{
private RealImage _image;
private readonly string _filename;
public ProxyImage(string filename)
{
_filename = filename;
}
public void Display()
{
if (_image == null)
10

{
_image = new RealImage(_filename);
}
_image.Display();
}
}
Приведём клиентский код, работающий с виртуальным заместителем:
IImage image1 = new ProxyImage("HiRes_10MB_Photo1");
IImage image2 = new ProxyImage("HiRes_20MB_Photo2");
image1.Display(); |
// выполняется загрузка |
||
image1.Display(); |
// загрузка не выполняется |
||
image2.Display(); |
// выполняется загрузка |
||
image2.Display(); |
// |
загрузка не |
выполняется |
image1.Display(); |
// |
загрузка не |
выполняется |
2.4. Компоновщик (Composite)
Шаблон Компоновщик позволяет упростить и стандартизировать взаимодействие между клиентом и группой объектов, представляющих древовидную структуру. Этот шаблон используется, если необходимо, чтобы клиент одинаково обращался как с составным объектом, так и с отдельными его частями.
Рассмотрим элементы шаблона Компоновщик (рис. 4). Интерфейс IComponent является общим для составных объектов и их частей. С точки зрения клиента все объекты являются экземплярами IComponent – клиент не различает составные объекты и их части. Класс Leaf представляет «неделимые» объекты (название взято по аналогии с наименованием элемента древовидной структуры). Класс Composite описывает составной объект, он может содержать как неделимые объекты, так и другие составные объекты.
<<interface>> IComponent
+Operation()
Leaf |
Composite |
|
-children:IComponent[0..*] |
+Operation() |
+Operation() |
Рис. 4. Дизайн шаблона Компоновщик.
Разберём пример использования шаблона Компоновщик. Пусть необходимо работать с картой, отдельные элементы которой реализуют интерфейс
IComponent.
11
public interface IComponent
{
string Title { get; set; } void Draw();
IComponent FindChild(string title);
}
public class MapComponent : IComponent
{
public string Title { get; set; }
public void Draw()
{
Console.WriteLine(Title);
}
public IComponent FindChild(string title)
{
return (Title == title) ? this : null;
}
}
Применим класс MapComposite, чтобы «собрать» фрагменты карты.
public class MapComposite : IComponent
{
private readonly List<IComponent> _map = new List<IComponent>();
public string Title { get; set; }
public void AddComponent(IComponent component)
{
_map.Add(component);
}
public void Draw()
{
Console.WriteLine(Title);
foreach (IComponent component in _map)
{
component.Draw();
}
}
public IComponent FindChild(string title)
{
if (Title == title)
{
return this;
}
12