![](/user_photo/2706_HbeT2.jpg)
GrandM-Patterns_in_Java
.pdf![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6271x1.jpg)
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 используется
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6272x1.jpg)
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 |
Virtual Ргоху • 279
ШАБЛОНЫ ПРОЕКТИРОВАНИЯ, СВЯЗАННЫЕ
С ШАБЛОНОМ VIRTUAL PROXY
Facade. Шаблон Facade может использоваться вместе с шаблоном Virtual Proxy для того, чтобы количество необходимых классов-заместителей бьvlО мини мальным.
Proxy. Шаблон Virtual Proxy - это специальная версия шаблона Proxy.
Object Pool. Шаблон Object Рооl можно использовать с той целью, чтобы по зволить многочисленным объектам ServiceProxy совместно использовать всего лишь несколько объектов
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6274x1.jpg)
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6275x1.jpg)
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6276x1.jpg)
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!
делегируют операции.
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6277x1.jpg)
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 может быть уместным также в том случае, когда имеются два конкретных класса-оберт ки, но не более того.
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6278x1.jpg)
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
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6279x1.jpg)
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 ; // Монитор этой камеры . |
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6280x1.jpg)
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, который разрешает вариации поведения не до или после вызова ме
тода, а во время обращения к методу.