Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

GrandM-Patterns_in_Java

.pdf
Скачиваний:
97
Добавлен:
14.03.2016
Размер:
8.88 Mб
Скачать

Virtual Ргоху 277

*/

public class CabinetAssistant implements CabinetAssistantIF ( public CabinetAssistant (String з) (

) // Cons t ructor ( S t ring)

public void operationl () {

} // operation l ( )

public void operation2 ( )

// operation2 ( )

}// clas s CabinetAs sistant

Интерфейс CabinetAssistantIF просто объявляет методы, определенные

классом CabinetAssi stant:

public interface CabinetAssistantIF public void operationl ( ) ;

public void operation2 ( ) ;

} // interface CabinetAss i s tant I F

И наконец, приведем код для класса CabinetAssi stantProxy, где и происхо­

дит все самое интересное:

public class CabinetAssistantProxy implements CabinetAssistantIF=

private CabinetAssistantIF assistant null ;

// Для конструктора объекта консультанта . private String myParam;

public CabinetAssistantProxy= (String з) { myParam з ;

} / / constructor ( String)

/**

*

*для реализации операций . Если он еще не существует ,

*/зтот метод создает его .Получаем объект CabinetAs sistan t, KOTopbrn используется

278

Глава 7. Структурные

ш

аблоны п

 

т

ирован

ия

 

 

 

 

роек

 

 

private CabinetAssistantIF getCabinetAssistant ()

 

if (assistant ==

null)

{

 

 

 

 

 

try//(

Получаем объект класса ,

 

 

 

//

который представляет класс Assistant .

 

Class

clazz ;

 

 

 

 

 

 

 

 

clazz = Class . forNarne ("CabinetAssistant") ;

 

// Получаем объект конструктора для доступа

 

//

к конструктору класса CabinetAs s i stant,

 

//

принимающему единственный строковьм аргумент .

 

Constructor constructor;

 

 

 

 

//

Получаем объект конструктора

 

 

//

для создания объекта

CabinetAs s i stant .

 

 

 

Class []

=

formalArgs ;

 

 

 

 

pararns

 

new Class

[ ] { String. class } ;

 

 

 

constructor = clazz . getConstructor (pararns) ;

 

 

 

// Исполь зуем объект конструктора .

 

 

 

Object[ ]

 

actuals

=

new Object [ ] { myPararn } ;

 

 

 

Assistant

= (CabinetAssistantIF)

 

 

 

constructor . newInstance (actuals) ;

 

 

 

catch

(Exception е)

{

 

 

 

// try

 

 

 

 

 

 

 

 

if

(assistant == null)

(

 

 

 

//

Обработка случая неуспешного создания

 

 

 

//

объекта CabinetAss i s tant .

 

 

 

throw new RuntimeException () ;

 

 

//

// i f

 

 

 

 

 

 

 

 

i f

 

 

 

 

 

 

 

return assistant;

 

 

}

//

getCabinetAs s i stant ( )

 

public void operationl ()

(

 

 

getCabinetAssistant () . operationl () ;

}

//

operationl ( )

 

 

 

public void operation2 ()

 

 

 

getCabinetAssistant () .

 

operation2 () ;

} / /

//

operation2 ( )

 

 

 

class

CabinetAs s i s t a n tProxy

Service.

Virtual Ргоху 279

ШАБЛОНЫ ПРОЕКТИРОВАНИЯ, СВЯЗАННЫЕ

С ШАБЛОНОМ VIRTUAL PROXY

Facade. Шаблон Facade может использоваться вместе с шаблоном Virtual Proxy для того, чтобы количество необходимых классов-заместителей бьvlО мини­ мальным.

Proxy. Шаблон Virtual Proxy - это специальная версия шаблона Proxy.

Object Pool. Шаблон Object Рооl можно использовать с той целью, чтобы по­ зволить многочисленным объектам ServiceProxy совместно использовать всего лишь несколько объектов

по крайней мере, одна камера следит за каждой входной дверью, связаннОЙ

Шаблон Decorator известен также как шаблон Wrapper. Он был ранее описан

в работе [GoF95].

СИНОПСИС

Шаблон Decorator расширяет функциональные возможности объекта, исполь­ зуя прозрачный для его клиентов способ: он реализует тот же самый интер­ фейс, что и исходный класс, и делегирует исходному классу операции.

КОНТЕКСТ

Предположим, необходимо разработать ПО дЛЯ системы безопасности, которая контролирует физический доступ в здание. Его основная архитектура такова, что устройство считывания карточек или другое устройство ввода данных полу­ чает некоторую идентификационную информацию и передает эту информацию объекту, контролирующему дверь. Если контролирующий дверь объект удовле­ творен информацией, он разблокирует дверь. На рис. 7.26 представлена диа­ грамма взаимодействия, описывающая этот механизм.

:DataEntry

-------

l:requestOpen(data:Strin'" ----

g

')----

 

 

 

i

theDoor:DoorControlLer2

Рис. 7.26. ОСНОВЫ контролирования физического ДОС1)'па

Допустим, нужно объединить этот механизм контроля доступа с системой на­

блюдения. Обычно в системе наблюдения намного больше подсоединенныХ

кней камер, чем телевизионных мониторов. Большинство мониторов периО­

дически показывают изображения, полученные от различных камер, демонстрИ­ руя картинку от одной камеры в течение нескольких секунд и затем переходя

кследующей камере, относящейся к этому монитору. Существуют некоторые

правила установки системы наблюдения, гарантирующие ее эффективность.

В данном случае рассмотрим следующие правила:

с системой контроля доступа;

каждый монитор отвечает только за одну камеру, следящую за входной две­

рью с контролируемым доступом. Эrо объясняется тем, что если за входнпоОЙ­

дверью будет следить несколько камер, то поломка одного монитора не

мешает просмотру изображений от всех камер на входной двери.

Decorator _ 281

Специальное требование интеграции заключается в том, что если контролирую­ lUий дверь объект получает запрос открыть дверь, то мониторы, отвечающие за камеры, направленные на эту входную дверь, показывают ее. Чтобы удовлетво­

рить это требование, можно расширить класс или написать несколько подклас­

сов (рис. 7.27).

«interface»F survеШапсеI

:---- -- _ _ _*L,---------i,

SurveiLLanceMonitorA I SurveiLLanceMonitorB I

«interface» DoorControLLerIF

 

t:.

 

,--------------,-- -- ---------.

I

I

:

DoorControLLerl

DoorControLLer2

I DооrCопtгоLLегЗI

Рис. 7.27. Классы системы безопасности

Установленные двери могут быть трех видов, а применяемые мониторы наблю­ дения могут соответствовать двум разным типам. Можно решить проблему, на­ писав два подкласса для каждого из классов контроллеров дверей. Однако са­ мое лучшее - не писать шесть классов, а использовать шаблон Decorator,

который решает эту задачу посредством делегирования, а не наследования.

Нужно написать два новых класса: DoorControllerWrapperA и DoorCon­ trollerWrapperB. Оба эти класса реализуют интерфейс DoorControllerIF (рис. 7.28). Они наследуют реализацию интерфейса DoorControllerIF от сво­

его абстрактного суперкласса AbstractDoorContro l lerWrapper.

 

г-__ р_асwи-'р"еТ______l

 

 

 

 

 

«interface»

 

 

 

 

.

i

DoorControLLerIF

.

.

 

-------L------

 

1

 

 

f:,.

 

 

 

I DооrCоп, tгоLLегз I

 

DoorControLLerl

DoorControLLer2

Рис. 7.28. Классы контроллера двери

I<.ласс AbstractDoorControllerWrapper реализует все методы интерфейса DoorControl lerIF, просто вызывая соответствующий метод другого объекта,

Реализующего интерфейс DoorControllerIF. Классы DoorControl lerA И

. актными. Они расширяют возможности поведения реализации requestOpen,

DoorControl lerB представляют собой классы-декораторы, не являющиеся аб­

282 Глава 7. Структурные шаблоны проектирования

унаследованного ими также для выдачи запроса монитору на отображение кар­ тинки обзора этой двери (рис. 7.29).

.1------.2: requestOpen(dat'---'----a:String)"'"'""'J1 thePoorjPoorControllerz I

I :PataEntry I1 l:requestOpen(data:String) :PoorControllerAJ

,-- :SurveiLlanceMonitorA====:; -- I I

1.1: viewNow(thePoor)

Рис. 7.29. Взаимодействие при набпюдении за дверью

Такой подход позволяет просматривать входную дверь при помощи нескольких

камер, которые должны управляться посредством простого размещения не­ скольких классов-декораторов перед объектом DoorControl lerIF.

МОТИВЫ

©Нужно расширитьоляюфункциональные возможности класса, однако существуют причины, не позв щие выполнить расширение при помощи наследования.

©Существует необходимость в динамическом расширении функциональных возможностей объекта.

РЕШЕНИЕ

На рис. 7.30 представлена диаграмма классов, на которой изображена основная

СТРУЮ1'ра шаблона Decorator.

Опишем роли, исполняемые классами и интерфейсом в шаблоне Decorator.

AbstractSeгviceIF. Интерфейс, выступающий в этой роли, реализуется всеми

объектами сервиса, которые потенциально могут быть расширены с помощьЮ

шаблона Decorator. Классы, экземпляры которых могут быть использованы для

динамически расширенных классов, реализующих интерфейс AbstractServiceIF,

тоже должны реализовывать интерфейс AbstractServiceI F.

ConcreteSeгvice. Классы, играющие эту роль, обеспечивают основную функ­

циональность, которая расширяется благодаря шаблону Decorator.

AbstractWrapperдля. Абстрактный класс, выступающий в этой роли, - это оБШИЙ

суперкласс классов-оберток. Экземпляры этого класса содержат таюке

ссылку на объект AbstractServiceIF, которому объекты ConcreteWrappe!

делегируют операции.

Decorator _ 283

 

 

 

 

 

 

 

 

 

 

 

 

 

 

«;nterface»

 

 

 

 

 

 

 

 

 

AbstractServiceIF

1

 

 

 

 

 

 

Operationl0

 

 

 

 

 

 

 

 

Operation20

 

 

 

 

 

 

 

...

 

 

 

....РасширяеТ

..------

 

 

 

 

 

I

_ _ _ _ _ _ _ _ _J_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _I

1

 

ConcreteService

 

 

 

 

 

AbstractWrapper

 

Operationl()

 

 

 

 

Operationl0

 

 

 

 

Operation2()

 

 

 

 

Operation2()

 

 

 

 

 

 

 

 

 

.. .

 

 

 

 

 

 

 

 

I

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

AbstractWrapperA

 

 

 

 

 

AbstractWrapperB

 

 

Operationl()

 

 

 

 

Operationl0

 

 

Operation20

 

 

 

 

Operation20

 

 

...

 

 

 

 

 

...

Рис. 7.30. Шаблон Decorator

Кроме того, этот класс обычно реализует все методы, объявленные интерфей­ сом AbstractServiceIF, поэтому они просто вызывают имеющий похожее имя метод объекта AbstractServiceIF, которому объект-обертка делегирует операции. Тем самым задается реализация по умолчанию для методов, функ­ циональность которых не изменяется.и т.д.

ConcreteWrapperA, ConcreteWrapperB Эти конкретные классы-обертки расширяют возможности поведения методов, унаследованного ими от класса

AbstractWrapper, любым приемлемым способом.

РЕАЛИЗАЦИЯ

 

я часть реализаций шаблона Decorator проще, чем общий случай. При­

Больша

ведем некоторые общие упрощенные варианты.

Если существует только один класс ConcreteService и нет класса АЬ­

stractService, то AbstractWrapper может быть подклассом класса Con­

creteService.

Если существует только один конкретный класс-обертка, нет необходимо­

сти в существовании отдельного класса AbstractWrapper. Можно объеди­ нить обязанности класса AbstractWrappe r с обязанностями конкретного

класса-обертки. Подобный отказ от класса AbstractWrapper может быть уместным также в том случае, когда имеются два конкретных класса-оберт­ ки, но не более того.

284 Глава 7. Структурные шаблоны праектирования

СЛЕДСТВИЯ

Шаблон Decorator предоставляет большую гибкость, чем наследование. Он позволяет динамически изменять поведение отдельных объектов, добаВЛЯJl

и убирая классы-обертки. С другой стороны, наследование определяет суть

всех экземпляров класса статическим образом.

©Используя различные комбинации декораторов нескольких видов, можно

задавать многочисленные комбинации поведения. Чтобы создать множест­

во различных видов поведения при помощи наследования, потребуется оп­

ределение множества различных классов.

Как правило, при использовании шаблона Decorator получается меНЬше

 

классов, чем при использовании наследования. Меньшее количество клас­

 

сов упрощает проектирование и реализацию программ. С другой стороны,

 

использование шаблона Decorator обычно приводит к большему количеству

®

объектов.

Из-за своей гибкости объекты декораторов более подвержены ошибкам, чем

 

 

унаследованные объекты. Например, существует вероятность такой комби­

 

нации объектов-оберток, при которой они не будут работать, или возможно

®

создание циклических ссылок между объектами декораторов.

Шаблон Decorator затрудняет использование уникальности объектов для

 

идентификации объектов сервиса, поскольку скрывает объекты сервиса за

 

объектами-декораторами.

ПРИМЕР КОДА

Приведем код, который реализует некоторые классы контроллеров дверей, представленные на диаграммах в разделе «Контекст». Реализация интерфейса

DoorControllerIF выглядит так:

interface DoorControllerIF

/**

* Запрашивает от рытие двери, если заданный люч подходит .

*/

public void requestOpen (Strinq key) ;

/*** За рывает дверь .

*/

public void close () ;

// i n t er face DoorCont rollerIF

Decorator 285

А теперь - класс Abs tractDoorControllerWrapper, который обеспечивает

ДЛЯ своих подклассов задаваемые по умолчанию реализации методов, объяв­ ленных интерфейсом DoorControllerIF:

abstract class AbstractDoorControllerWrapper implements DoorControllerIF

private DoorControllerIF wrappee ;

/ * *

 

*

Cons t ructor

*

@param wrappee Объект , которому этот объект будет

*

делегировать операции .

* /

 

AbstractDoorControllerWrapper= (DoorControllerIF wrappee) ( this . wrappee wrappee ;

/ / constructor (wrappee)

/ * * * Запрашивает открытие двери, если данный ключ подходит . * / public void requestOpen (Strinq key) (

wrappee . requestOpen (key) ;

}/ / reques tOpen ( String )

/ * *

*Закрывает дверь .

*/

public void close ()

wrappee . close () ;

/ / close ( )

} / / class AbstractDoorControllerWrapper

и наконец, подкласс класса AbstractDoorControllerWrapper, который рас­ Ширяет заданное по умолчанию поведение, запрашивая монитор с целью ото­ БРажения картинки от указанной камеры:

class DoorControllerWrapperA

extends AbstractDoorControllerWrapper

private

Strinq camera ; //

Задаем имя камеры, просматривающей

 

//

эту дверь .

private

SurveillanceМonitorIF monitor ; // Монитор этой камеры .

286 Глава 7. Структурные шаблоны проектирования

/ * *

 

 

 

 

*

 

Cons tructor

 

 

 

*

 

@param wrappee Объект DoorContro l ler,

которому этот объект

*

 

 

будет делегировать

операции .

*

 

@param camera Идентификатор камеры, про сматривающей эту

*

 

дверь .

 

 

*

 

@param moni tor

Монитор, эапрашиваемьrn

для просмотра

*/

 

картинки от камеры .

 

 

 

 

 

DoorControllerwrapperA(DoorControllerIF wrappee ,

 

 

 

String camera ,

 

 

 

 

SurveillanceМonitorIF monitor)

 

super (wrappee) ;

 

 

 

this . camera = camera ;

 

 

 

this . monitor =

monitor;

 

 

 

// cons t ructor (wrappee)

 

 

/ * *

 

 

 

 

*

/

 

 

 

 

*

 

Запрашивает открытие двери, если дaHHьrn ключ подходит .

public void requestOpen (String key)

{

 

 

monitor . viewNow (camera) ;

 

 

 

super. requestOpen(key) ;

 

 

//

/ / reques tOpen ( St ring)

 

 

class DoorControllerWrapperA

 

 

ШАБЛОНЫ ПРОЕКТИРОВАНИЯ, СВЯЗАННЫЕ

С ШАБЛОНОМ DECORATOR

Delegation. Шаблон Decorator представляет собой структурный способ приме­

нения шаблона Delegation.

Filter. Шаблон Filter - это специальная версия шаблона Decorator, предназна­

ченная для обработки потока данныхдля.

Strategy. Шаблон Decorator полезен дополнительных действий до или по­

сле обращения к методамдругогообъекта. Если необходимы какие-то действИЯ

во время обращения к методу, рекомендуем рассмотреть использование шаблона

Strategy.

Template Method. Template Method - это альтернативный вариант шаблона

Decorator, который разрешает вариации поведения не до или после вызова ме­

тода, а во время обращения к методу.

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