Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Design Patterns via C#.pdf
Скачиваний:
154
Добавлен:
17.03.2016
Размер:
13.25 Mб
Скачать

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). Эта оптимизация очень похожа на технику создания объектов по требованию, она позволяет экономить ресурсы при копировании больших и сложных субъектов. Если проводить действия с суррогатом субъекта вместо оригинала (может требовать значительно меньше вычислительных ресурсов чем действия с оригиналом) и организовать отложенное копирование таким образом, чтобы оно производилось только тогда, когда окончена модификация суррогата и он отличается от первоначального оригинала, то можно существенно уменьшить плату за копирование «тяжелых» субъектов.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]