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

GrandM-Patterns_in_Java

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

"*

 

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 е) {

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

throw new ExceptionlnlnitializerError (e) ;

// try

//static

/* *

* Нарезает пищу ломтиками заданной ширины .

* /

public void slice (int width) (

/ / s l ice ( int)

/* *

* Смешивает пищу с заданной скоростью . * /

public void mix (int speed) {

}

/ / mix ( in t )

/ * *

*

Взвешивает пищу .

* Возвращает вес в унциях . * / public double weigh= () ( double weight 0 . 0;

return weight;

/ / weight ( )

/ * * * Запускает указанную программу . * / void run (String programName) (

// Создаем ClassLoader для загрузки классов программы .

// Если эти классы больше не нужны,

// то они могут быть удалены сборщиком мусора .

URLClassLoader= ClassLoader;

ClassLoader new URLClassLoader (classPath) ;

Class programClass; try ( =

programClass ClassLoader . loadClass (programName) ;

Dynamic Linkage - 269

}

catch (ClassNotFoundException е) {

/ /

Не найден .

return;

}

/ / t ry

AbstractFoodProcessorProgram program;

try (

 

program = (AbstractFoodProcessorProgram)

 

programClass . newlnstance () ;

}

catch (Exception е) (

 

/ / Запуск невозможен .

return;

/ / try

program. setEnvironment (this) ; display (program. getName (» ; program. start () ;

/ / run ( Stri ng)

} / / class FoodProcessorEnvironment

и наконеи, пример кода для класса верхнего уровня программы:

public class ConcreteFoodProcessorProgram extends AbstractFoodProcessorProgram / * *

*Возвращает имя зтого объекта программы приготовления пищи .

*/

public String getName () { return "Chocolate Мilk"; }

/ * * * Вызов этого метода сообщает программе приготовления

* пищи о начале ее работы .

* /

 

 

 

public void start ()

 

 

double weight

= getEnvironment {) . weigh ( ) ;

if (weight >

120

. 0

&& weight < 160 . 0)

getEnvironment ( ) .mix (4) ;

/ / start ( )

/ / class ConcreteFoodProcessorProgram

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

ШАБЛОНЫ ПРОЕКТИРОВАНИЯ, СВЯЗАННЫЕ С ШАБЛОНОМ DYNAМIC LINКAGE

Virtual Proxy. Реализация шаблона Virtual Proxy иногда использует шаблон Dynamic Linkage для загрузки класса, который нужен ему для создания своего основного объекта.

Protection Proxy. Шаблон Protection Proxy (описанный в книге [Grand2001])

иногда используется вместе с шаблоном Dynamic Linkage с целью минимиза­

ции риска, связанного с нарушением системы безопасности.

Этот шаблон ранее был описан в работе [Larman98].

СИНОПСИС

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

своих клиентов тот факт, что объект еще может не существовать, предоста

им косвенный доступ к объекту, осуществляемый через объект-заместитель, реализующийВ тот же интерфейс, что и объект, который может не существовать.

данном случае используется «ленивое» инстанциирование.

КОНТЕКСТ для

Предположим, что группа программистов пишет объемный Jаvа-апплет компании , управляющей сетью больших хозяйственных магазинов. Этот ап­ плет позволит людям покупать при помощи интернета все, что продается в этих магазинах. Помимо предложенного каталога апплет предусматривает исполь­ тоз вание, различных помощников, позволяющих потребителям выбрать именно

что им нужно. Эта помощь, например, включает:

консультанта по кухонным шкафам, помогающего потребителю подобрать набор шкафов и затем автоматически заказать все детали, необходимые для сборки шкафов;

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

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

покрытия.

Таких помощников на самом деле намного больше, и апплет получается очень объемный. Из-за своих размеров он требует от браузера недопустимо большого КОличества времени на загрузку при использовании модемного соединения.

Один из способов уменьшения времени загрузки апплета заключается в том, ЧТОбы не загружать каких-либо консультантов до тех пор, пока они не потребу­ IOТся . Шаблон Virtual Рюху предлагает способ задержки загрузки части апплета 'fаким способом, который прозрачен для остальной части апплета. Идея заклю­ Чается в том, что остальная часть апплета обращается к классам, входящим

8 Состав консультанта, не прямо, а косвенно, через класс-заместитель. Клас­ сыIзаместители и специально создаются так, чтобы не содержать какой-либо

CabinetAss i stantProxy

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.

 

 

 

 

Virtual Ргоху 273

МОТИВbI

© Инстанциирование класса требует много времени.

© Инстанциирование класса может не потребоваться.

© Если существует несколько классов, экземпляры которых не потребуются

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

© Управление отложенным инстанциированием классов не должно быть воз­

ложено на клиентов класса. Поэтому отложенное инстанциирование класса должно быть прозрачным для его клиентов.

® Иногда самый лучший способ обеспечить хорошую производительность

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

РЕШЕНИЕ

На рис. 7.24 показана организация классов, которые участвуют в шаблоне

Virtual Proxy.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Использует

 

 

 

 

1

«;nterface»

 

 

 

 

 

 

 

 

 

 

 

 

 

ServiceIF

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Использует

1

 

 

 

 

 

 

 

 

 

 

 

 

operationl0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

operation20

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1 ..*

 

 

 

 

 

 

 

 

 

 

...

 

 

 

ServiceHeLperl

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

*

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

l

Пiепt

1

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

II

 

Использует

 

 

 

 

 

 

 

 

II _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ L _ _ _ _ II

 

 

 

 

 

 

 

 

 

I

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

1

 

I

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

ServiceProxy

 

 

 

 

II

 

1

 

 

 

 

 

 

operationl0

 

 

 

 

Service

 

 

 

 

 

 

 

1

operation20

 

 

 

)

operationl0

 

 

 

 

 

 

 

.

.

.

 

 

1

 

C! l!.a!!

 

1

 

 

 

 

 

 

 

 

_

operation20

 

 

 

 

 

 

 

 

 

 

 

 

 

_ _

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

Рис. 7.24. Шаблон Virtual Рroху

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).

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

I

Client

I

1 ..*

Использует" 1 '1J

ИСПОЛl,зует ..

1 .

Р

I

Sемсе

roxy 1 1

ServicePackage I

«interface»

 

 

1

.1

 

 

I

"l

+ServiceIF

 

 

 

11I

 

 

 

 

 

 

I

1

1

 

 

 

 

 

I

 

Создает" _...1

I

 

1

"1

 

+Service

 

 

1

 

 

 

 

I

-SеrviсеНеlреrl

Использ

т ..

* Т

уе

 

 

1 Использует ..

!

I -Sеrvi*сеНеlреr2

I

I

Рис. 7.25. Отношение становится явным при использовании пакета

СЛЕДСТВИЯ

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

© нужны. тех

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

©Классы, использующие заместитель, не нуждаются в сведениях о том, за­ rpужен ли класс Service, существует ли его экземпляр или даже существует

ли сам класс.

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

доступ к предоставляемому классом Service сервису косвенно, через за­

местителя. Это очень важно. Если хотя бы один класс обращается к класпосу­

Service напрямую, то класс Service будет заrpужаться до того, как он

требуется на самом деле. В этом заключена скрытая ошибка, которая обыч­

но влияет на производительность, а не на саму функциональность, и поэто­

му ее очень трудно отследить.

ПРИМЕР КОДА

Чтобы завершить пример, начатый в разделе «Контекст», приведем код, реали­

зующий консультанта по шкафам и класс заместителя. Сначала - соответст­

вующий код для класса CabinetAs si stant:

/**

 

* Это класс сервиса ,

используемый виртуальным заместителем .

* Класс реализует интерфейс , написанный исключитель но

* для объявления методов этого класса .

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