- •Предисловие 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
- •Библиография
99
объект класса Adapter невозможно использовать там, где может использоваться объект класса
Adaptee.
Имеется разновидность адаптеров, которые называются двусторонними адаптерами (twoway adapters). Двусторонние адаптеры способны обеспечить возможность использовать адаптер TwoWayAdapter там, где мог использоваться Adaptee.
Интерфейс двустороннего адаптера (класса TwoWayAdapter) представляет собой объединение интерфейсов адаптируемых друг к другу классов AdapteeNew и AdapteeOld.
См. Пример к главе: \006_Adapter\005_TwoWayAdapter
Реализация
Имеется три подхода к реализации сменных адаптеров. Эти способы проще рассмотреть на примере использования пользовательского элемента управления TreeDisplay, для автоматического отображения иерархических древовидных структур (TreeDisplay уже был описан выше).
Первый подход – использование абстрактных операций.
При таком подходе в теле абстрактного класса-цели TreeDisplay необходимо задать абстрактный метод Display, с аргументом типа object, значение аргумента должно представлять собой ссылку на иерархическую структуру. Метод Display, в данном случае, формирует «узкий» интерфейс для адаптируемых классов со встроенными адаптерами: AssemblyTreeDisplay и DirectoryTreeDisplay. Другими словами, метод Display представляет собой наименьшее подмножество операций, позволяющих выполнить адаптацию, и его реализация фактически является оберткой над специфическими методами адаптируемых классов AssemblyTreeDisplay и DirectoryTreeDisplay, которые позволяют осуществлять доступ к иерархической структуре сборки проекта и структуре каталогов файловой системы.
См. Пример к главе: \006_Adapter\006_3_AdaptersForTreeDisplay
Второй подход – использование объектов-уполномоченных.
Для того чтобы реализовать данный подход потребуется создать специальные объекты – «объекты-уполномоченные». Тогда класс TreeDisplay сможет переадресовывать запросы для доступа к иерархической структуре этим объектам-уполномоченным, при этом, реализовывая различные стратегии адаптации путем использования необходимых конкретных уполномоченных. Например, одним из таких объектов-уполномоченных для класса TreeDisplay мог бы быть класс DirectoryBrowser. В статически типизированных языках, которым и является C#, потребуется явно задать интерфейс, который необходим классу TreeDisplay, например, interface ITreeAccessorDelegate, и реализовать этот интерфейс в выбранном классе-уполномоченном
DirectoryBrowser.
Третий подход – адаптеры, конфигурируемые при помощи параметров.
Этот подход предоставляет возможность использования конструкции switch или нескольких условных конструкций if-else в теле адаптера, как альтернативу наследованию при реализации
100
сменных адаптеров. Такой подход позволяет реализовывать механизмы адаптации без порождения подклассов. Применимо, к рассматриваемому примеру это означает, что в классе TreeDisplay может быть два условных блока: первый блок, для преобразования узла в тип GraficNode, а второй блок – для доступа к потомкам узла.
Пример кода
Предлагается рассмотреть реализацию адаптера уровня класса и адаптера уровня объекта на примере, из раздела «Мотивация»:
В классе Shape создается абстрактный фабричный метод CreateManipulator, с возвращаемым значением типа Manipulator. Manipulator обладает функциональностью по анимированию объектов класса Shape в ответ на действия пользователя. В классе Shape также создается абстрактный метод BoundingBox, который отвечает за отображение элементов типа
Shape на форме (TextShape и Line).
public abstract class Shape
{
public abstract void BoundingBox();
public abstract Manipulator CreateManipulator();
}
Абстрактный класс Manipulator реализует взаимодействие и контролирует состояние объекта-манипулятора. Манипуляторы представлены как наследники базового класса Control.
public abstract class Manipulator : Control
{
//состояние манипулятора на форме.
public Point StartPoint { get; protected set; } public Point EndPoint { get; protected set; }
//задание базовых параметров контрола public Manipulator()
{
SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.SupportsTransparentBackColor, true); SetStyle(ControlStyles.Opaque, true);
this.BackColor = Color.Transparent; this.DoubleBuffered = false;
}
//определяет параметры необходимые при создании контрола protected override CreateParams CreateParams
{
get
{
const int WS_EX_TRANSPARENT = 0x00000020; CreateParams createParams = base.CreateParams; createParams.ExStyle |= WS_EX_TRANSPARENT; return createParams;
}
}
}
Класс TextView содержит метод GetExtend, который отвечает за отображение объектов на форме, этот метод является аналогом метода BoundingBox, а аналог фабричного метода для создания манипулятора в классе TextView отсутствует. Таким образом для работы с классом TextView в проекте необходимо использовать класс-адаптер TextShape, который адаптирует интерфейс класса TextView к интерфейсу класса Shape.
101
class TextView
{
Label label;
public TextView()
{
label = new Label();
}
public Label GetExtend()
{
label.ForeColor = Color.DarkMagenta;
label.Font = new Font(label.Font, label.Font.Style | FontStyle.Bold); label.BorderStyle = BorderStyle.None;
label.TextAlign = ContentAlignment.TopLeft; label.FlatStyle = FlatStyle.Standard; label.AutoSize = true;
return label;
}
}
class TextShape : Shape
{
Point startPoint; string text; TextView textView; Label label;
public TextShape(Point startPoint, string text)
{
textView = new TextView(); this.startPoint = startPoint; this.text = text;
}
//Преобразование запроса BoundingBox в запрос GetExtend. public override void BoundingBox()
{
label = textView.GetExtend(); label.Text = text;
}
//Фабричный метод, возвращающий манипулятор соответствующий
//конкретной фигуре
public override Manipulator CreateManipulator()
{
return new TextManipulator(startPoint, label);
}
}
Поскольку в классе TextView не предусмотрен метод для создания манипулятора, который будет работать с текстом, то необходимо такой метод реализовать самостоятельно. В классе TextShape реализация метода CreateManipulator не использует повторно никакой функциональности из класса TextView.
class TextManipulator : Manipulator
{
102
Label textInside;
private int deltaX, deltaY; Point currentMouse;
bool mousePressed = false;
//Метод, возвращающий глобальные координаты курсора на
//контроле относительно формы
Point GetMouseLocation(Point curMouse)
{
return new Point(curMouse.X + this.Location.X, curMouse.Y + this.Location.Y);
}
// Перерисовка манипулятора
void ReDrawControl(Point startPoint)
{
Size = new Size(textInside.Text.Length * 8, textInside.Size.Height); Location = startPoint;
RecreateHandle();
Refresh();
}
public TextManipulator(Point startPoint, Label label)
{
textInside = label; StartPoint = startPoint; ReDrawControl(startPoint); Controls.Add(textInside);
textInside.MouseDown += TextInside_MouseDown; textInside.MouseUp += TextInside_MouseUp;
}
// Методы обработчики базового класса Manipulator
void TextInside_MouseDown(object sender, MouseEventArgs e)
{
OnMouseDown(e);
}
void TextInside_MouseUp(object sender, MouseEventArgs e)
{
OnMouseUp(e);
}
// Метод, определяющий новые координаты манипулятора на форме protected override void OnMouseUp(MouseEventArgs e)
{
if (mousePressed)
{
base.OnMouseUp(e);
deltaX = GetMouseLocation(e.Location).X - currentMouse.X; deltaY = GetMouseLocation(e.Location).Y - currentMouse.Y;
StartPoint = new Point(StartPoint.X + deltaX, StartPoint.Y + deltaY); ReDrawControl(StartPoint);
currentMouse = GetMouseLocation(e.Location);
103
}
else
mousePressed = false; Cursor = Cursors.Arrow;
}
// Определение координат текущего манипулятора по клику protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
currentMouse = GetMouseLocation(e.Location); mousePressed = true;
Cursor = Cursors.Hand;
}
}
См. Пример к главе: \006_Adapter\002_DrawingEditor