- •Предисловие 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
- •Библиография
158
Участники
Proxy - Заместитель:
Представляет собой класс объекта-заместителя. Объект заместитель хранит в себе ссылку на реальный субъект, что позволяет заместителю обращаться к реальному субъекту напрямую. Заместитель имеет такой же интерфейс, как и реальный субъект, что позволяет в нужный момент подставлять заместителя вместо реального субъекта и наоборот. Заместитель контролирует доступ к реальному субъекту и может отвечать за создание экземпляра реального субъекта если это может оказаться необходимым. Прочие обязанности заместителя зависят от вида заместителя. Заместители бывают четырех видов: удаленный заместитель (посол), виртуальный заместитель, защищающий заместитель и заместитель – умная ссылка.
Subject - Субъект:
Предоставляет общий интерфейс для Proxy и RealSubject. Proxy возможно использовать везде где ожидается использование RealSubject.
RealSubject - Реальный субъект:
Представляет собой класс объекта, для которого требуется создание заместителя.
Отношения между участниками
Отношения между классами
Класс RealSubject связан связью отношения наследования с абстрактным классом Subject.
Класс Proxy связан связью отношения наследования с абстрактным классом Subject и связью отношения ассоциации с классом RealSubject.
Отношения между объектами
Объект-заместитель класса Proxy, переадресует клиентские запросы целевому объекту класса
RealSubject.
Мотивация
Предлагается рассмотреть редактор документов, который позволяет встраивать в документ изображения (графические объекты). При отображении графических объектов большого размера могут возникать задержки. Но документ должен открываться быстро, поэтому не следует создавать сразу все графические объекты на стадии открытия документа, а создавать их только тогда, когда потребуется показать изображение пользователю.
Вместо реального изображения, можно временно использовать его упрощенный суррогат (заместитель). В роли заместителя можно использовать изображение с более низким разрешением (preview или thumbnail), которое быстрее отобразится на странице в момент, когда изображение станет видимым пользователю.
Например, при использовании EBookDroid (программа просмотра документов и электронных книг) можно увидеть эффект задержки полного отображения новой страницы. Такая задержка может быть связана с аппаратной составляющей (слабый процессор, мало памяти).
На рисунке видно, что, в момент «перелистывания» страниц, на появившейся странице (снизу) контент отображается с более низким разрешением чем на странице (сверху).
У разработчиков приложения может быть несколько вариантов организации отображения новой страницы: Первый вариант - отобразить пустую страницу и ожидать пока загрузится контент. Второй вариант – отображать информацию на странице по мере загрузки, что тоже заставляет ждать пользователя. Третий вариант – показать пользователю страницу в более низком качестве, при этом пользователь по очертаниям и силуэтам может принять решение – остаться на данной странице и ожидать ее полной загрузки или продолжить «листать» книгу.
159
Применимость паттерна
Паттерн Proxy рекомендуется использовать, когда требуется воспользоваться целевым объектом не напрямую, а через объект-заместитель.
Объект-заместитель имеет четыре технологические разновидности:
Удаленный заместитель («Посол» или «Ambassador»).
Удаленный объект-Proxy – это объект, который находится в другом адресном пространстве относительно целевого объекта и обеспечивает доступ к целевому объекту. Например, при использовании технологии WCF создается объект прокси представляющий собой обертку для сервиса-потребителя (consumer), который связывается с сервисом-поставщиком (provider).
160
class Server |
class Client |
|
{ |
{ |
|
static void Main() |
static void Main() |
|
{ |
{ |
|
Console.Title = "SERVER"; |
Console.Title |
= "CLIENT"; |
Uri address = new Uri("http://localhost:4000/ISubject"); |
Uri address = |
new Uri("http://localhost:4000/ISubject"); |
BasicHttpBinding binding = new BasicHttpBinding(); |
BasicHttpBinding binding = new BasicHttpBinding(); |
|
Type contract = typeof(ISubject); |
EndpointAddress endpoint = new EndpointAddress(address); |
|
ServiceHost host = new ServiceHost(typeof(RealSubject)); |
ChannelFactory<ISubject> factory = |
|
host.AddServiceEndpoint(contract, binding, address); |
new ChannelFactory<ISubject>(binding, endpoint); |
|
host.Open(); |
|
|
|
// Использование factory для создания канала |
|
Console.WriteLine("Приложение готово к приему сообщений."); |
// channel - суть proxy Ambassador. |
|
Console.ReadKey(); |
ISubject channel = factory.CreateChannel(); |
|
host.Close(); |
// Использование proxy для отправки |
|
} |
// сообщения предназначенного realsubject. |
|
} |
channel.Say("Hello WCF!"); |
|
|
} |
|
|
} |
|
|
[ServiceContract] |
|
|
interface ISubject |
|
|
{ |
|
|
[OperationContract] |
|
|
void Say(string input); |
|
|
} |
|
class RealSubject |
: ISubject |
{ |
|
public void Say(string input) |
|
|
|
{ |
|
|
|
Console.WriteLine("Сообщение: |
{0} - получено. |
", |
input); |
} |
|
|
|
}
Runtime Type
Proxy
См. Пример к главе: \012_Proxy\005_Ambassador
Виртуальный заместитель.
Виртуальный заместитель - это объект, который создает «тяжелые» объекты по требованию. Как бывает в жизни. Например, человек хочет приобрести автомобиль. Прежде чем его купить, клиент обычно пользуется объектом-заместителем этого автомобиля, а именно буклетом, который описывает автомобиль. И только после того как клиент убедится, что это именно то что ему требуется, едет в автосалон на «test-drive». Пример и техническое описание виртуального заместителя представлены в разделе «Мотивация».
См. Пример к главе: \012_Proxy\002_ImageProxy
Защищающий заместитель.
Защищающий заместитель, контролирует доступ к своему целевому объекту. Такие заместители используются, когда требуется установить различные права доступа к целевому объекту. Например, при реализации подхода CRUD популяризированного Джеймсом Мартином. CRUD – (Create, Read, Update, Delete – Создание, Чтение, Обновление, Удаление).
См. Пример к главе: \012_Proxy\ 003_ProxyCRUD
Заместитель «Умная ссылка».
Объект «умная ссылка» - представляет собой объектно-ориентированное представление обычного указателя (адреса переменной или метода в памяти). В качестве примера умной ссылки в языке C# можно привести такие синтаксические конструкции как делегат (delegate), критическая секция (lock), оператор автоматической генерации программного кода итератора (yield), переменная запроса LINQ, операторы автоматической генерации программного кода асинхронного выполнения метода (async и await). Предлагается рассмотреть каждую из упомянутых конструкций, представляющую собой неявное выражение паттерна Proxy вида «умная ссылка».
Делегат (delegate) как «умная ссылка», представляет собой функциональноориентированную сущность в объектно-ориентированном представлении, предназначенную для
хранения и передачи указателя (адреса первого байта тела метода в памяти) на метод. Умность
161
делегата заключается в том, что программисту не требуется напрямую работать с числовым представлением адреса первого байта тела метода, а также в наличии дополнительной функциональности которая обслуживает хранящийся в делегате указатель. Но не принято «языком ООП» говорить, что мы вызываем метод по указателю содержащемся в делегате, правильно сказать, что мы вызываем метод сообщенный с делегатом. Вызывая метод Invoke, говорят: - «Мы вызываем метод сообщенный с делегатом.» (подразумевая синхронный вызов метода), а вызывая метод BeginInvoke говорят: - «Мы асинхронно вызываем метод сообщенный с делегатом.».
Критическая секция (lock) как «умная ссылка», представляет собой безопасную конструкцию по работе с объектом синхронизации доступа к разделяемому ресурсу, между несколькими потоками (нитями). Умность конструкции lock заключается в том, что она избавляет программиста использовать напрямую вызовы методов Monitor.Enter и Monitor.Exit, использование которых напрямую зачастую приводит к трудно обнаруживаемым ошибкам.
Оператор автоматической генерации программного кода итератора (yield) как «умная ссылка», представляет собой быстрый и безопасный способ получения объекта-итератора. Умность оператора yield заключается в том, что программисту не требуется утруждать себя пониманием устройства сложного итератора, например, создание внутреннего (пассивного) итератора вручную, не всегда оказывается легкой задачей.
Переменная запроса LINQ, как «умная ссылка», представляет собой переменную содержащую ссылку на коллекцию, которую возвращает связанное с ней (ней - переменной запроса) выражение запроса LINQ. Умность переменной запроса LINQ заключается в том, что она принимает в себя ссылку на коллекцию (другими словами инициирует выполнение выражения запроса) только тогда, когда эту переменную начинают использовать фактически, если в процессе выполнения программного модуля к переменной запроса не будет произведено обращение, то и выражение запроса не будет выполняться исполняющей средой. Понятно, что любое выражение запроса LINQ трансформируется в последовательность вызовов расширяющих методов, которые могут формировать определенную коллекцию, как результат своего выполнения, что не всегда может положительно сказаться на производительности в случае хаотичного или одновременного выполнения всех имеющихся выражений запроса в программе.
Связка операторов автоматической генерации программного кода, обслуживающего асинхронное выполнение метода (async и await) как «умная ссылка», представляют собой генератор машины состояния для асинхронного выполнения. Умность связки async и await заключается в том, что большинство рутинных операций по организации асинхронной обработки эта связка берет на себя. Например, организация «асинхронной машины состояний» (конечного автомата, обслуживающего асинхронные вызовы – реализация методов MoveNext и SetStateMachine интерфейса IAsyncStateMachine), организация цепочек «продолжений» асинхронного выполнения нескольких операций и др.
Результаты
Паттерн Proxy позволяет дополнительно защитить (скрыть) субъект при попытке доступа к нему, добавляя уровень косвенности во взаимоотношениях объектов. В зависимости от варианта применения паттерна можно выделить следующие полезные особенности:
удаленный заместить может скрывать реальное расположение субъекта от клиента (в адресном пространстве диска или в памяти).
виртуальный заместитель может оптимизировать ресурсы, создавая субъекты по требованию,
реализуя технику отложенной (или ленивой) инициализации.
защищающий заместитель и «умная» ссылка позволяют проводить дополнительные действия
(например, верификацию, валидацию, кеширование и т.п.) при попытке доступа к субъекту.
Дополнительно паттерн Proxy может скрывать от клиента возможность копирования при записи (copy-on- write). Эта оптимизация очень похожа на технику создания объектов по требованию, она позволяет экономить ресурсы при копировании больших и сложных субъектов. Если проводить действия с суррогатом субъекта вместо оригинала (может требовать значительно меньше вычислительных ресурсов чем действия с оригиналом) и организовать отложенное копирование таким образом, чтобы оно производилось только тогда, когда окончена модификация суррогата и он отличается от первоначального оригинала, то можно существенно уменьшить плату за копирование «тяжелых» субъектов.