- •Предисловие 15
- •Предисловие
- •От авторов
- •Об авторах
- •Благодарности
- •Принятые в книге обозначения
- •Технические рекомендации
- •Дополнительные ресурсы
- •Глава 1. Введение
- •1.1. Понятие паттерна проектирования
- •Определение
- •Метафора
- •1.2. Формат описания паттернов проектирования
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Известные применения паттерна в .Net
- •1.3. Каталог паттернов проектирования
- •Порождающие
- •Структурные
- •Поведенческие
- •1.4. Техники ООП
- •Фабрика - Продукт
- •Фасад - Подсистема
- •Диспетчеризация
- •Цепочка объектов
- •Издатель-Подписчик
- •1.5. Принципы организации каталога
- •Цель паттерна
- •Уровень паттерна
- •1.6. Рекомендации по изучению паттернов
- •1.7. Рекомендации по применению паттернов
- •Глава 2. Порождающие паттерны
- •Игра - Лабиринт
- •Паттерн Abstract Factory
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода игры «Лабиринт»
- •Известные применения паттерна в .Net
- •Паттерн Builder
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода игры «Лабиринт»
- •Известные применения паттерна в .Net
- •Паттерн Factory Method
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода игры «Лабиринт»
- •Известные применения паттерна в .Net
- •Паттерн Prototype
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода игры «Лабиринт»
- •Известные применения паттерна в .Net
- •Паттерн Singleton
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода игры «Лабиринт»
- •Известные применения паттерна в .Net
- •Глава 3. Структурные паттерны
- •Паттерн Adapter
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Adapter уровня классов
- •Adapter уровня объектов
- •Структура паттерна на языке C#
- •Adapter уровня классов
- •Adapter уровня объектов
- •Участники
- •Отношения между участниками
- •Отношения между классами (для адаптера уровня классов)
- •Отношения между классами (для адаптера уровня объектов)
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Adapter уровня классов
- •Adapter уровня объектов
- •Особенности применения паттерна Adapter
- •Реализация
- •Пример кода
- •Известные применения паттерна в .Net
- •Паттерн Bridge
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Паттерн Composite
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Известные применения паттерна в .Net
- •Паттерн Decorator
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Известные применения паттерна в .Net
- •Паттерн Facade
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Паттерн Flyweight
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Известные применения паттерна в .Net
- •Паттерн Proxy
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Известные применения паттерна в .Net
- •Глава 4. Паттерны поведения
- •Паттерн Chain of Responsibility
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Паттерн Command
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Известные применения паттерна в .Net
- •Паттерн Interpreter
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Паттерн Iterator
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Классическое представление
- •Представление Microsoft .NET
- •Структура паттерна на языке C#
- •Классическое представление
- •Представление Microsoft .NET
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Известные применения паттерна в .Net
- •Паттерн Mediator
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Паттерн Memento
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Реализация
- •Паттерн Observer
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Модель вытягивания (Pull model)
- •Модель проталкивания (Push model)
- •Структура паттерна на языке C#
- •Модель вытягивания (Pull model)
- •Модель проталкивания (Push model)
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Реализация
- •Пример кода
- •Известные применения паттерна в .Net
- •Паттерн State
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Мотивация
- •Применимость паттерна
- •Результаты
- •Паттерн Strategy
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Применимость паттерна
- •Паттерн Template Method
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Применимость паттерна
- •Результаты
- •Реализация
- •Паттерн Visitor
- •Название
- •Также известен как
- •Классификация
- •Частота использования
- •Назначение
- •Введение
- •Структура паттерна на языке UML
- •Структура паттерна на языке C#
- •Участники
- •Отношения между участниками
- •Отношения между классами
- •Отношения между объектами
- •Применимость паттерна
- •Результаты
- •Реализация
- •Известные применения паттерна в .Net
- •Библиография
282
На представленной ниже диаграмме взаимодействия показаны отношения между объектами: клиентом (Program), объектной структурой (ObjectStructure), посетителем (ConcreteVisitor) и двумя элементами (ConcreteElementA и ConcreteElementB).
См. Пример к главе: \023_Visitor\001_Visitor
Применимость паттерна
Паттерн Visitor рекомендуется использовать, когда:
В (гетерогенной) коллекции (ObjectStructure) должны присутствовать разнотипные объекты (ConcreteElementA и ConcreteElementB) с разнородными интерфейсами и при этом требуется организовать унифицированный обход элементов этой коллекции и выполнить определенные операции над каждым имеющимся объектом.
283
class ObjectStructure { // Подчеркиваетсяя гетерогенность. ArrayList elements = new ArrayList();
public void Add(Element element) { elements.Add(element); }
public void Remove(Element element) { elements.Remove(element); }
public void Accept(Visitor visitor) { foreach (Element element in elements) element.Accept(visitor); } }
Над объектами (ConcreteElementA и ConcreteElementB) входящими в состав коллекции (ObjectStructure) требуется выполнять определенные операции и при этом не хотелось бы повторять эти операции в каждом классе (ConcreteElementA и ConcreteElementB). Код этих операций можно вынести в методы объекта посетителя класса ConcreteVisitor.
class ConcreteVisitor : Visitor
{
public override void VisitElementA(ElementA elementA)
{
//Код который мог быть размещен в классе ElementA,
//расширяет собой класс ElementA. elementA.SomeState = "State A"; Console.WriteLine(elementA.SomeState);
//Работа с разнородным интерфейсом. elementA.OperationA();
}
public override void VisitElementB(ElementB elementB)
{
//Код который мог быть размещен в классе ElementB,
//расширяет собой класс ElementB. elementB.SomeState = "State B"; Console.WriteLine(elementB.SomeState);
//Работа с разнородным интерфейсом. elementB.OperationB();
}
}
Классы объектов (ConcreteElementA и ConcreteElementB), входящих в коллекцию (ObjectStructure) изменяются редко, но новые операции, производимые над коллекцией требуется добавлять часто. Важно понимать, что при изменении интерфейса классов объектов (ConcreteElementA и ConcreteElementB), входящих в состав коллекции, вероятней всего потребуется переопределить и интерфейсы всех объектов посетителей (ConcreteVisitor1 и
ConcreteVisitor2), а это может быть затруднительно. Поэтому, если классы (ConcreteElementA и ConcreteElementB) изменяются часто, то лучше все операции определять прямо в них (т.е., не выносить операции в посетителей).
284
Пример отображающий идеи применимости паттерна Visitor, рассмотренные выше.
class Program
{
static void Main()
{
ObjectStructure structure = new ObjectStructure();
structure.Add(new ElementA()); structure.Add(new ElementB());
structure.Accept(new ConcreteVisitor());
}
}
|
abstract class Visitor |
|
|
{ |
|
|
public abstract void VisitElementA(ElementA elementA); |
|
|
public abstract void VisitElementB(ElementB elementB); |
|
class ObjectStructure |
} |
|
{ |
|
|
// Подчеркиваетсяя гетерогенность. |
|
|
ArrayList elements = new ArrayList(); |
|
|
public void Add(Element element) |
class ConcreteVisitor : Visitor |
|
{ |
||
{ |
||
public override void VisitElementA(ElementA elementA) |
||
elements.Add(element); |
||
{ |
||
} |
||
// Код который мог быть размещен в классе ElementA, |
||
|
||
public void Remove(Element element) |
// расширяет собой класс ElementA. |
|
elementA.SomeState = "State A"; |
||
{ |
||
Console.WriteLine(elementA.SomeState); |
||
elements.Remove(element); |
||
|
||
} |
// Работа с разнородным интерфейсом. |
|
|
||
public void Accept(Visitor visitor) |
elementA.OperationA(); |
|
} |
||
{ |
||
|
||
foreach (Element element in elements) |
public override void VisitElementB(ElementB elementB) |
|
element.Accept(visitor); |
||
{ |
||
} |
||
// Код который мог быть размещен в классе ElementB, |
||
} |
||
// расширяет собой класс ElementB. |
||
|
||
|
elementB.SomeState = "State B"; |
|
|
Console.WriteLine(elementB.SomeState); |
|
|
// Работа с разнородным интерфейсом. |
|
|
elementB.OperationB(); |
|
|
} |
|
|
} |
abstract class Element
{
public abstract void Accept(Visitor visitor); public string SomeState { get; set; }
}
class ElementA : Element |
class ElementB : Element |
{ |
{ |
public override void Accept(Visitor visitor) |
public override void Accept(Visitor visitor) |
{ |
{ |
visitor.VisitElementA(this); |
visitor.VisitElementB(this); |
} |
} |
public void OperationA() |
public void OperationB() |
{ |
{ |
Console.WriteLine("OperationA"); |
Console.WriteLine("OperationB"); |
} |
} |
} |
} |
См. Пример к главе: \023_Visitor\003_Visitor
285
Результаты
Паттерн Visitor обладает следующими преимуществами:
Упрощение добавления новых методов.
Используя объекты-посетители, легко добавлять новую функциональность объектам-элементам. Понятно, что функциональность, предназначенная для объектов-элементов, физически будет находиться в методах объекта-посетителя, создавая иллюзию расширения самого класса элементов новой функциональностью. Для добавления новой операции (функциональности) всем или некоторым объектам-элементам, потребуется создать новый класс посетителя или изменить один из существующих классов посетителей.
Объединение сходного поведения.
Сходное поведение (функциональность) относящееся к объектам-элементам, не разносится по всем классам (ConcreteElement), а локализуется (размещается) в классе объекта-посетителя. Не связанная друг с другом функциональность распределяется по отдельным конкретным классам (ConcreteVisitor). Такой подход позволяет упростить как сами классы элементов (ConcreteElement), так и алгоритм, располагающийся внутри посетителя (все данные которые относятся к алгоритму можно располагать непосредственно в посетителе, т.е. рядом с алгоритмом).
Накопление состояния.
Посетитель может накапливать в себе информацию о состоянии элементов, входящих в объектную структуру. Если не использовать паттерн Visitor, то состояние придется передавать в виде дополнительных (ref/out) параметров методов, выполняющих обход и сохранять в специально отведенном месте, что может вызвать определенные неудобства.
Паттерн Visitor обладает следующими недостатками:
Сложность добавления новых классов ConcreteElement.
При использовании паттерна Visitor, возникают некоторые сложности при добавлении новых классов элементов (ConcreteElement). Связано это с тем, что создание нового класса ConcreteElement, требует добавления нового абстрактного метода VisitConcretElementX в абстрактный класс Visitor, этот абстрактный метод потребуется реализовать во всех производных классах ConcreteVisitor.
При принятии решения об использования паттерна Visitor, потребуется определиться, что чаще будет добавляться в подсистему: алгоритм (новая функциональность) применяемый к элементам (ConcreteElement) входящим в объектную структуру или сами классы этих элементов (ConcreteElement). Если чаще будет добавляться алгоритм, то паттерн Visitor, поможет лучше управлять такими изменениями. Если же, планируется часто добавлять новые классы элементов (ConcreteElement), то вероятно, что такую модель классов сопровождать будет не удобно, но вполне возможно.
Разрушение инкапсуляции.
При работе с элементами (ConcreteElement), объект-посетитель в большинстве случаев должен знать их внутреннее устройство, для того чтобы справиться со своей работой по расширению функциональности. Поэтому при использовании паттерна Visitor, требуется организовывать более широкий чем мог бы быть, открытый интерфейс взаимодействия с объектами (ConcreteElement), что естественно, разрушает инкапсуляцию.