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

GrandM-Patterns_in_Java

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

 

 

Flyweight 8 257

/ * *

 

*

Возвращает символ , который представляет

этот объект .

* /

 

puыlcc char getChar ()

 

 

return characteri

 

}

/ / getChar ( )

 

/**

 

*

Этот метод возвращает уникальное значение , которое

*

определяет место внутреннего хранения в

хэш-таблице .

*/

puыlcc int hashCode () return getChar () i

} / / hashCode ( )

/** * Переопределяем равенство таким образом, что два объекта

*DocChar считаются равными, если они представляют

*один и тот же символ .

*/

puыlcc boolean equals (Object о} (

// Не прямым образом обращаемся к символу, а вызываем

// метод getChar с тем, чтобы этот метод соответствовал

//какому-либо имеющемуся у подкласса альтернативному

//методу предоставления описываемого им символа . return (о instanceof DocChar

"« DocChar} o) . getChar () -- getChar ( » ;

}// equa l s (Obj ect)

}// class DocChar

инаконец, приведем код для класса DocCharFactory, который отвечает за со8местное использование объектов DocChar:

class DocCharFactory (

 

private MutableDocChar myChar = new МutableDocChar () i

/**

 

* Коллекция ранее созданных объектов DocChar .

*/

= new HaahМap () ;

private HaahМap docCharPool

/*

*

*

Возвращает объект DocChar, представляющий данный символ .

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

* /

synchronized DocChar getDocChar (char с ) { myChar . setChar (c) =;

DocChar thisChar (DocChar) docCharPool . get (myChar) ; if (thisChar === null) {

thisChar new DocChar (c) ; docCharPool . put (thisChar, thisChar) ;

/ / i f

return thisChar;

// getDocChar ( char)

qтобы разрешить поиск объектов DocChar В HashMap или аналогичной коллек­ ции, следует предъявить коллекции объект DocChar, описываюший тот же символ, что и объект DocChar, который нужно найти в коллекции. Создание объекта DocChar при выполнении каждой операции поиска означало бы, что все еще создается объект DocChar для каждого символа документа. Хотя поэти­ объекты DocChar были бы удалены программой сборки мусора, поскольку сле их участия в операции поиска на них нет больше ссьи1ОК, но В первую оче­ редь все же лучше вообще отказаться от их создания.

Альтернативой созданию объекта DocChar при выполнении каждой операции поиска должно стать многократное использование одного и того же объектано­ DocChar при условии изменения представляемого им символа для каждого вого поиска. Проблема, возникающая при изменении описываемого объектом

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

DocChar .

Класс DocCharFactory выходит из этого затруднения, используя такой закры­

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

сываемого им символа:

private static class МutableDocChar extends DocChar { private char character ;

МutableDocChar () {

// Не имеет значения , что передаем конструктору . super ( '\uOOOO' ) ;

} / / Cons t ructor {char)

/**

* Возвращает символ , описываемый этим объектом . */

public char getChar () return character;

Flyweight - 259

} / / getChar ( )

/ * * * Задаем символ , описываемый этим объе том . * /

public void setChar= (char с) { character с ;

}/ / setChar (char)

// class MutableDocChar

//class DocCha rFactory

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

дляComposite. Шаблон Ayweight часто используется вместе с шаблоном Composite представления листьев иерархической структуры при помоши совместно

используемых объектов. дЛЯ

Factory Method. Шаблон Flyweight использует шаблон Factory Method соз­ дания новых объектов-приспособленцев.

СасЬе Management. Реализация класса FlyweightFactory может использо­ вать кэш.

ImmutabIe. Совместно используемые объекты-приспособленцы часто бывают неизменными.

СИНОПСИС

Позволяет программе в ответ на запрос загружать и использовать ПРОИЗВОЛЬные классы, реализующие известный интерфейс.

КОНТЕКСТ

Предположим, создается программа для нового вида интеллектуального пище­ вого процессора, в который можно загружать сырые ингредиентьr, и он, нарезая ломтиками, кубиками, смешивая, отваривая, выпекая, зажаривая и помеши­ вая, способен производить готовую к употреблению пищу. На механическомдля уровне новый пищевой процессор - очень сложное оборудования. Однако пищевого процессора очень важен выбор программ для приготовления различ­ ной пищи. Программа, при помощидля которой можно смешивать муку, воду, дрожжи и другие ингредиенты получения различных видов хлеба, значи­ тельно отличается от программы, при помощи которой можно поджаривать, помешивая, креветки в строгом соответствии с нужным рецептом. Пищевой процессор должен запускать множество различных программ, которые позво­ ляют ему готовить разнообразную пищу. При этом невозможно встроить в пи­ щевой процессор все необходимые программы, поэтому пищевой процессор должен загружать программы с CD-ROM или аналогичных носителей.

Чтобы такие динамически загружаемые программы и операционная среда пи­

щевого процессора могли работать вместе, им нужен способ, позволяющий вы­ зывать методы друг друга. На рис. 7. 19 представлена диаграмма классов, реа­ лизующая такую возможность.

 

 

L 1

 

 

 

....Испо

льзует

 

 

 

1

 

 

 

 

 

FoodProcessorEnvironmentIF

 

 

setEnvironment{environment:FoodProcessorEnvironmentIF)

 

 

 

«intemce»

 

 

 

 

 

 

 

 

AbstractFoodProcessorProgram

 

 

slice{)

 

 

 

 

 

getName()

 

 

 

 

 

 

 

 

mix{)

 

 

 

 

 

start()

 

 

 

 

 

 

 

 

 

weigh{)

 

 

 

...

 

Т

 

r1

 

 

. . .

 

 

 

 

Испольэует

1

 

 

 

 

 

 

 

 

 

I

I

1

 

 

 

 

 

 

 

 

 

 

 

 

FoodProcessorEnvironment

 

 

 

 

I (oncreteFoodProcessorProgram I

 

 

 

Рис.

7.19.

Классы для программы пищевого процессора

 

Dynamic Linkage 261

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

пКТищевого процессора, обращаясь к методам его суперкласса. Кроме того, объ­

е верхнего уровня может вызывать методы объекта среды процессора через

реализуемый им интерфейс FoodProcessorEnvironmentIF. На рис. 7.20 изо­

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

программы.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

I

 

 

1.1: programClass :- forName(programName:String)

 

 

Class

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.2: program :- newlnstance()

 

 

 

 

 

 

 

 

 

 

 

II

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

programClass:Class

 

 

 

 

 

 

 

1.3: setEnvironment(env)

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

1.4: name :- getName()

 

 

 

 

 

 

 

 

 

 

 

 

1.6: start()

 

 

:...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

program:ConcreteFoodProcessorProgram

 

 

 

 

 

 

 

 

 

:

 

1.6.1:Weigh()

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1: run(programName:String) I

 

 

 

 

 

 

 

 

 

 

 

 

1.6.2:mix()

 

 

 

 

 

 

 

!:!!Jl;F!!!!dпюРr!!пm!:пt

!:ШI[.Е. .

 

 

I

 

 

I

 

 

 

 

 

 

 

 

 

 

 

:DispLav

 

 

 

 

 

I

 

1.5:disрIaуPro9ramName name

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.

Рис. 7.20. Взаимодействие классов пищевого процессора

Операционная среда пищевого процеса получает запрос на запуск про­ граммы с заданным именем.

1.1.Среда вызывает метод forName класса Class, передавая ему имя запускаемой программы. Метод forName находит объект Class (с таким же, как и у программы, именем). В случае необходимо­ сти он загружает класс с CD-ROM. Метод forName завершается, возвращая объект Class, в котором инкапсулирован класс верх­

него уровня этой программы.

1.2.Среда создает для программы экземпляр класса верхнего уровня. tla диаграмме этот экземпляр указан под именем program.

1.3.Среда передает ссылку на саму себя методу setEnvironment

объекта program. Если программе передана такая ссылка, про­

грамма может обращаться к методам операционной среды.

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

1.4.Из программы операционная среда получает имя программы.

1.5.Операционная среда отображает имя программы на экране.

1.6.Операционная среда запускает программу.

1.6.1.Программа взвешивает описанные в ней ингредиенты .

1.6.2. Программа смешивает описанные в ней ингредиенты.

Программа продолжает работать, выполняя последующие шаги, которые УЖе не имеют отношения к данной схеме.

МОТИВЫ

©Программа должна иметь возможность загружать и использовать произ­

вольные классы, о которых она ничего не знает заранее.

©Экземпляры загруженного класса должны иметь возможность обратного вызова программы, загрузившей его.

®Добавление в программу классов, которые не были предусмотрены при ее создании, связано с риском потери безопасности. Кроме того, существует риск несоответствия класса и программы ввиду несовпадения используе­ мых версий.

РЕШЕНИЕ

На рис. 7.2 ] показана диаграмма классов, на которой представлены роли ин­ терфейсов и классов, принимающих участие в шаблоне Dynamic Linkage.

 

1

 

Использует

«interface))

 

 

EnvironmentIF

 

 

operationl0

 

 

 

operation20

 

 

 

. ..

 

 

 

 

 

 

Использует

I

 

 

 

I

I

1

 

I

 

I

 

 

 

Environment

1 1

AbstractLoadableClass

setEnvironment(:EnvironmentIF)

start()

 

l Т

I

 

. ..

 

 

 

 

I

 

 

 

I

 

 

 

II

 

 

I

,

I

 

ConcreteLoadabLeCLass

Рис. 7.21. Шаблон Dynamic Linkage

Опишем эти роли.

EnvironmentlF. Интерфейс, выступающий в этой роли, объявляет методы

ды, которые могут быть вызваны загруженным классом.

сре­

кл а с с ы
Environment.

Dynamic linkage 263

J1JEnvironmentУЖает . Класс в этой роли представляет собой часть среды, которая за­ класс ConcreteLoadableClass. Он реализует интерфейс EnvironmentIF.

Ссылка на экземпляр этого класса передается экземплярам класса Concre­ teLoadableClass , поэтому они могут вызывать методы объекта Envi ronment, объявляемые интерфейсом EnvironmentIF.

AbstractLoadabIeClass. Любой класс верхнего уровня, объявленный в програм­ ме пищевого проuессора, должен быть подклассом некоторого класса, высту­

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

1 . Метод, с именем, например, setEnvironment, который позволяет эк­ земплярам подклассов класса AbstractLoadableClass получить ссылку на экземпляр класса, реализующего интерфейс EnvironmentIF. Назна­ чение этого метода состоит в том, чтобы позволить объектам АЬ­ stractLoadableClass вызывать методы объекта

2.Метод, обычно с именем start, вызывается средой, чтобы сообщить экземпляру загруженного класса о начале его работы.

ConcreteLoadabIeClass. Классы в этой роли являются динамически загружае­ мыми подклассами класса AbstractLoadableClass.

РЕАЛИЗАЦИЯ

оПредставленный шаблон Dynamic Linkage считает, что среда должна знать

классе AbstractLoadableClass и что загруженный класс должен знать об

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

способе взаимодействия с бином (Ьеап).

Другое требование шаблона Dynamic Linkage состоит в ТОМ , что класс Envi­ ronment должен каким-то образом узнать имя класса, который он хочет загру­

яхзить. Механизм выяснения имени зависит от приложения. В некоторых случа­

с имена могут быть заданы с помощью аппаратных средств. В примере

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

ределяющий расположение катологов программ на CD-ROM или другом ди­

СТРибутивном носителе. Пищевой npoцессор показывает каталог программ в виде Меню, позволяя пользователю сделать выбор.

Н ес о вм ес т и м ые

Некоторые случаи реализации шаблона Dynamic Linkage ДОЛЖНЫ принимать во

Внимание то, ЧТО различные динамически загруженные классы могут использо­ Вать несовместимые версии ОДНОГО и того же класса. Предположим, что про­ Граммы приготовления лазаньи и пельменей поступают на разных носителях

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

иобе используют утилитный класс Fu. Однако два класса с именем Fu несовмес_ тимы друг с другом. Допустим, что пишевой процессор сначала запускает про­ грамму приготовления лазаньи, а затем пытается запустить программу изготов­ ления пельменей. Если при загрузке программы по изготовлению пельменей ему предоставляется класс Fu для программы по изготовлению лазаньи, про­ грамма по изготовлению пельменей работать не будет.

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

Р и с к , с в я з а н н ы й с н а руш е н и е м б е зо п а с н ости

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

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

которые возможные риски.

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

целей.

Класс может делать что-то, что нарушает целостность его среды. Такие нарушения могут принимать самые разные формы. по­

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

Первый, требуюший решения, вопрос заключается в том, чтобы оценить велИ­ чину риска в конкретном случае. Если вероятность неправильного хода соБЫ­ тий достаточно мала или последствия достаточно незначительны, то не стоИТ предпринимать каких-либо мер, чтобы уменьшить вероятность или последСТ­

вия возникновения проблем с безопасностью. С другой стороны, если вероЯТ­

 

 

ет

ность плохого хода событий или последствия достаточно велики, то следу

принять все возможные меры.

 

 

то

конкретный кл

асс

Следуюший вопрос, какова вероятность того, что какой-

 

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

Dynamic Unkage 265

СОСТОИТ В том, можно или нельзя разрешить использовать класс в некоторой среде. В Java за загрузку классов отвечает подкласс абстрактного класса j ava . 1ang . ClassLoader. Документация к этому классу содержит подробное

описание механизма загрузки классов.

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

Jдavaм, обладает тщательно разработанным механизмом контроля доступа к мето­

а основанном на доверии и полномочиях. Он описан в документе «Java 2

Platform Security Architecture» , который входит в комплект документации, по­ ставляемый компанией Sun вместе с Java 2 SDK

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

не доверяют, делать то, что они не должны делать. В качестве дополнительной

меры можно использовать защитный прокси-класс, описанный в книге д[Grand2001]о туп . Таким образом даже классы, которым доверяют, могут получить

с только к определенным вещам.

СЛЕДСТВИЯ

©

Подклассы класса AbstractLoadableClass могут загружаться динамиче­

©

ски.

Операционная среда и загруженные классы не нуждаются в какой-либо оп­

ределенной предварительной информации друг о друге.

Динамическая компоновка увеличивает общее время, которое нужно про­

 

грамме для загрузки всех используемых ею классов. Однако здесь может

 

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

®

ни. С этой целью уместно использование шаблона Virtual Рroху.

Использование шаблона Dynamic Linkage связано с риском нарушения сис­

 

 

темы безопасности.

ПРИМЕНЕНИЕ В JAVA API

Web-браузеры используют шаблон Dynamic Linkage для запуска апплетов.

На рис. 7.22 представленадиаграмма классов, описывающая отношения между ilnnлетом и браузером.

Операционная среда браузера имеет доступ к заrpуженному ею подклассу класса

ЛРРlеt как к экземпляру класса Applet. Заrpуженные подклассы апплета по­

JJУчают доступ к среде браузера через интерфейс AppletStub.

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

 

 

 

 

 

 

 

 

"Использует

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

«interface»

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

I

 

 

I

 

 

AppLet

I

 

 

 

AppLetStub

 

 

1

 

 

 

ь. 1

 

 

Использует·

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I BrowserAppLetEnvironment

I

I

 

 

 

 

 

1 1_----J

 

MyAppLet

 

 

Рис. 7.22.

Апплеты и брауэеры

 

 

 

 

ПРИМЕР КОДА

Приведем код, который реализуетдля проект пишевого процессора, описанный вразделе «KoнтeKCn. Интерфейс операционной среды пишевого процессора:

public interface FoodProcessorEnvironmentIF ( /* *

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

*/

publiC void slice (int width) ;

/**

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

*/

public void mix (int speed) ; / * *

*Вэвешивает пищу .

*Воэвращает вес в унциях .

*/

public double weight () ;

} // inte rface FoodProcessorEnvironmentI F

Напишем абстрактный класс, который является суперклассом ДЛЯ всех классоВ

верхнего уровня программы:

public abstract class AbstractFoodProcessorProgram private FoodProcessorEnvironmentIF environment;

/**

*

Операционная среда пищевого процессора передает этому

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