![](/user_photo/2706_HbeT2.jpg)
GrandM-Patterns_in_Java
.pdf![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6261x1.jpg)
"* |
|
Dynamic Unkage • |
267 |
|
|
||
|
методу ссылку на саму себя , |
|
|
"* |
|
что позволяет экземплярам подклассов этого класса |
|
"* |
|
вызывать методы объекта среды пищевого процессора , |
|
"* |
/реализующего интерфейс FoodProcessorEnvi ronment I F . |
|
|
public void setEnvironment ( |
|
||
|
|
FoodProcessorEnvironmentIF environment) ( |
|
|
this . environment = environment; |
|
|
|
// setEnvironment ( FoodProcessorEnvironmentIF) |
|
|
/"*"* |
|
||
"*/ |
|
||
|
|
Разрешает подклассам считать ссылку н а операционную среду . |
|
protected FoodProcessorEnvironmentIF getEnvironment () ( |
|
||
|
return environment; |
|
|
|
// getEnvironment ( ) |
|
|
/"*"* |
|
|
|
. |
/ |
Возвращает имя этого объекта программы приготовления пищи . |
|
"* |
|
||
public aЬ_tract String getName () |
|
||
/ . "* |
|
||
"* |
|
при вызове этого метода программа приготовления |
|
• |
пищи получает сообщение о начале работы . |
|
|
. |
/ |
|
|
public aЬstract void start ()
}// class AbstractFoodProcessorProgram
Приведем класс, который позволяет операционной среде пищевого процессора
запускать программы. Он использует объект ДIIЯуправления за ГРуЖаемыми им классами.
public class FoodProcessorEnvironment
implements FoodProcessorEnvironmentIF//
private static final U Я L[] classPath ; URL для программы .
static |
= new U R L [ ]{new U R L <<file:( ///bin») } ; |
try |
|
classPath |
} catch (java . net.мa1formedURLException е) {
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6262x1.jpg)
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6263x1.jpg)
210 • Глава 7. Структурные шаблоны nроектирования
ШАБЛОНЫ ПРОЕКТИРОВАНИЯ, СВЯЗАННЫЕ С ШАБЛОНОМ DYNAМIC LINКAGE
Virtual Proxy. Реализация шаблона Virtual Proxy иногда использует шаблон Dynamic Linkage для загрузки класса, который нужен ему для создания своего основного объекта.
Protection Proxy. Шаблон Protection Proxy (описанный в книге [Grand2001])
иногда используется вместе с шаблоном Dynamic Linkage с целью минимиза
ции риска, связанного с нарушением системы безопасности.
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6265x1.jpg)
Этот шаблон ранее был описан в работе [Larman98].
СИНОПСИС
Если инстанциирование объекта требует больших затрат. а объект может не по требоваться, то имеет смысл отложить его инстанциирование доРюхутех пор, пока онет станет действительно ясно, что объект нужен. Шаблон Virtual скрывляяает
своих клиентов тот факт, что объект еще может не существовать, предоста
им косвенный доступ к объекту, осуществляемый через объект-заместитель, реализующийВ тот же интерфейс, что и объект, который может не существовать.
данном случае используется «ленивое» инстанциирование.
КОНТЕКСТ для
Предположим, что группа программистов пишет объемный Jаvа-апплет компании , управляющей сетью больших хозяйственных магазинов. Этот ап плет позволит людям покупать при помощи интернета все, что продается в этих магазинах. Помимо предложенного каталога апплет предусматривает исполь тоз вание, различных помощников, позволяющих потребителям выбрать именно
что им нужно. Эта помощь, например, включает:
•консультанта по кухонным шкафам, помогающего потребителю подобрать набор шкафов и затем автоматически заказать все детали, необходимые для сборки шкафов;
•консультанта, помогающего определить, сколько пиломатериалов потребу ется покупателю для строительства настила;
•консультанта для определения размера коврового покрытия, соответствую щего определенной планировке, и наилучшего способа разрезания этого
покрытия.
Таких помощников на самом деле намного больше, и апплет получается очень объемный. Из-за своих размеров он требует от браузера недопустимо большого КОличества времени на загрузку при использовании модемного соединения.
Один из способов уменьшения времени загрузки апплета заключается в том, ЧТОбы не загружать каких-либо консультантов до тех пор, пока они не потребу IOТся . Шаблон Virtual Рюху предлагает способ задержки загрузки части апплета 'fаким способом, который прозрачен для остальной части апплета. Идея заклю Чается в том, что остальная часть апплета обращается к классам, входящим
8 Состав консультанта, не прямо, а косвенно, через класс-заместитель. Клас сыIзаместители и специально создаются так, чтобы не содержать какой-либо
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6266x1.jpg)
212 • Глава 7. Структурные шаблоны проектирования
статической ссылки) на класс, заместителями которого они являются. Это оз,
начает, что, если классы-заместители загружены, нет ни одной ссылки на
класс, для которого эти классы являются заместителями. Если остальная
часть апплета ссылается только на заместителей, а не на классы, реалИЗУЮЩИе
консультантов, то Jаvа-машина не должна автоматически загружать консуль,
тантов.
При вызове метода заместителя он сначала обеспечивает загрузку и инстанции,
рование классов, реализующих консультанта. Затем он вызывает соответствую,
ЩИЙ метод через интерфейс.
На рис. 7.23 изображена основная часть апплета, которая ссылается на класс
CabinetAs s i s tantProxy, реализующий интерфейс CabinetAss i s tantIF.
Основная часть апплета не содержит ссьmок на классы, реализующие консуль танта по шкафам. В случае необходимости класс
обеспечивает загрузку и инстанциирование классов, реализующих консультанта по шкафам. Код, реализующий этот механизм, приводится в разделе « Пример кода».
|
|
|
|
|
|
|
|
|
«interface» |
||||
|
|
|
|
|
|
|
|
|
CabinetAssistantIF |
||||
|
|
|
|
|
|
Использует |
|
|
|||||
|
|
|
|
|
|
|
operationl{) |
|
|
|
|||
|
|
|
|
|
|
..-----operation2{)1 |
|||||||
|
|
1 |
|
|
|
|
|
|
|
||||
|
|
|
|
|
CabinetAssistantProxy |
|
CabinetAssistant |
|
|
||||
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
operationl{) |
|
|
|
|
||||
|
|
|
|
|
|
operationl{) |
|
|
|||||
|
|
|
|
|
operation2{) |
|
operation2{) |
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Рис. 7.23. Класс-заместитель консультанта по шкафам
Под статической ссылкой автор понимает ссылку на класс, который компилятор бу
дет распознавать на стадии компиляции. Например,
Foo myFoo;
это статическая ссылка на класс Foo. Сравните со статической ссьUIКОЙ на Foo из сле
дующего примера:
Class c l a z z |
|
Clas s . forName (" Foo" ) ; |
|
|
|||
В этом примере компьютер в |
|
|
Строка не |
||||
|
= |
|
мя класса |
|
идит строку, |
которая содержит имя класса. |
|
распознается как и |
|
до тех пор. пока не начнется стадия выполнения и не бу |
|||||
дет вызван метод forName. |
|
|
|
|
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6267x1.jpg)
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6268x1.jpg)
27.4 • Глава 7. Структурные шаблоны проектирования
Опишем роли, исполняемые этим интерфейсом и классами.
Service. Класс Service обеспечивает логику верхнего уровня для предостаВЛяДРУГJfее
мого им сервиса. При создании экземпляра этого класса класс создает
объекты, которые ему нужны. Такие классы указаны на диаграмме как Ser viceHelperl , ServiceHelper2 .
Client. Класс Cl ient использует сервис, предоставляемый классом Service.
Классы Client никогда прямо не используют класс Service. Вместо этого они используют класс ServiceProxy, обеспечиваюший функциональность клаСса
Service. Косвенное использование класса Service делает клиентские классы
нечувствительными к тому, сушествует ли уже экземпляр класса Service, кос венно используемый объектами Client.
ServiceProxy. Задача класса ServiceProxy состоит в задержке создания эк земпляров класса Service до тех пор, пока они действительно не понадобятся.
Класс ServiceProxy обеспечивает косвенность между классами Cl ient И клас
сом Service. Косвенность скрывает от объектов Cl ient тот факт, что если создан объект ServiceProxy, то соответствуюший объект Service не сущест
вует, а класс Service может даже и не быть загружен.
Объект ServiceProxy отвечает за создание соответствуюшего объекта Service и создает объект Service при первом же запросе на выполнение операции, требуюшей наличия объекта Service.
Класс ServiceProxy пишется специально для получения доступа к классу Service через динамическую ссылку. Обычно классы ссылаются на другие классы при помоши статических ссылок. Статическая ссылка просто содержит имя класса, который находится в соответствуюшем месте исходного кода. Ко гда компилятор видит ссылку такого рода, он автоматически загружает другой класс вместе с классом, содержашим ссьmку на него.
Шаблон Virtual Ргоху препятствует загрузке класса Service И связанных с ним
классов вместе с остальной частью программы, гарантируя, что эта остальная
часть программы не содержит каких-либо статических ссылок на класс Ser vice. Вместо этого остальная часть программы ссьmается на класс Service че
рез класс ServiceProxy, а класс ServiceProxy ссьmается на класс Service
при ПОмощи динамической ссьmки.
Динамическая ссьmка содержит вызов метода, передаюшего строку с именем
класса методу, загружающему этот клтакихсс, если он еше не загружен, и возврашает
ссьmку на этот класс. Как правило, в случаях вызывается статический метод j ava . lang . class . forName. Поскольку имя класса может находиться только
внутри строки, то компиляторы не знают, на какой класс нужно будет ссьmаТЬСЯ,
и поэтому они не генерируют сигнал, заставляюший класс загружаться.
ServiceIF. Класс ServiceProxy создает экземпляр класса Service, вызывая методы, не требующие каких-либо статических ссылок на класс Service.
Класс ServiceProxy тоже обрашается к методам класса Service, не имея ка
ких-либо статических ссылок на класс Service. Он вызывает методы класса
Servi ce благодаря тому, что класс Service реализует интерфейс ServiceI F.
Virtual Ргоху • 275
trИнтерфейс ServiceIF объявляет все методы, реализуемые классом Service необходимые для класса ServiceProxy. Поэтому объект ServiceProxy r,tожет рассматривать создаваемую им ссылку на объект Service как ссылку на объект ServiceIF. Класс Service использует статические ссылки на интер
фейс ServiceIF для вызова методов объектов Service. Никакие статические ссылки на класс Service не нужны.
РЕАЛИЗАЦИЯ
С о вм е с т н о и с п ол ьзуе м ы е о бъ е кт ы с е р в и са
Согласно этому решению, когда объекту ServiceProxy впервые поступает за прос на выполнение некоторой операции, он создает объект Service и впо следствии постоянно будет иметь ассоциируемый с ним объект Servi ce. Но если объект Service требует на время своего существования большого объема памяти или много разных ресурсов, то нецелесообразно создавать столько объ
ектов Service, сколько имеется объектов ServiceProxy.
Если обьекты Service не имеют состояний и взаимозаменяемы, то можно рас смотреть возможность использования шаблона Object Рооl с целью сведения к ми
нимуму количества объектов Service, которые создает разработчик. Идея за ключается в том, что, когда объекту ServiceProxy для выполнения некоторой операции нужен объект Service, он получает объект Service из пула объек
товект. Когда объект Service заканчивает выполнение требуемой операции, объ ServiceProxy возвращает его назад в пул объектов. Этот способ позволяет иметь множество объектов Se'rviceProxy и всего лишь несколько объектов
Service.
Отл оже н н а я з а г руз ка кл а сс а
Во многих случаях класс, доступный через виртуальный заместитель, применяет
Другие классы, которые не используются остальной частью программы. При та ких отношениях эти классы не загружаются до тех пор, пока не будет загружен КЛасс, доступный через виртуальный заместитель. Если важно, чтобы такие КЛассы не загружались, пока не будет загружен класс, доступный через вирту алЬный заместитель, то проблема может возникнуть на этапе имплементации. fIрограммист может добавить прямую ссьmку на один из таких классов, не за думываясь о последствиях. Если тесты программы, проверяющие ее качество,
Не включают тестирование производительности, проблема может остаться не замеченной до тех пор, пока не поступят жалобы от пользователей этой про Граммы.
Можно уменьшить вероятность такого хода событий, сделав отношение между КЛассами явным. Для этого можно поместить упомянутые классы в пакет, при "ем видимым за пределами пакета может быть только один используемый за J.fестителем класс (рис. 7.25).
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6270x1.jpg)