GrandM-Patterns_in_Java
.pdf;* * * Метод регистрирует получателя будущих
Bгidge _ 237
* /данных измерений от этого сенсора .
public void addStreamingSensorListener ( StreamingSensorListener listener)
//listeners . addElement (listener) ; addStreamingSensorListener ( StreamingSensorLi s tener)
/***Этот метод отменяет регистрацию получателя
*/будущих данных от этого сенсора .
public void removeStreamingSensorListener ( StreamingSensorListener listener)
/listeners/ . removeElement(listener) ;
/**
addSt re amingSensorLis tener ( StreamingSen sorListener)
* Этот метод асинхронно удаляет измеренные значения
*/из канала и передает их зарегистрированным получателям .
public void run () while (true) (
int value ; try
value = consumer . readInt () ;
catch (IOException е) |
|
// |
Канал не работает, поэтому выходим из метода , |
/ / |
что приводит к окончанию выполнения потока . |
/ / |
try |
return;
for (int i=O ; i < listeners . size () ; i++) StreamingSensorListener listener; listener
=(StreamingSensorListener) listeners . elementAt (i) ;
|
|
|
/ / for |
|
|
/ / |
listener.procesSМ8asurement (value) ; |
// |
} |
while |
|
/ / |
run ( ) |
||
c l a s s |
StreamingSensor |
238 |
• Глава 7. Структурные шаблоны проектироваНИR |
|
Чтобы класс StreamingSensor мог передавать измерение объекту, необходи мо, чтобы этот объект реализовывал интерфейс StreamingSensorListener. Измерения передаются методу processMeasurement, который объямен ин
терфейсом StreamingSensorListener. Класс StreamingSensor тоже реали зует интерфейс StreamingSensorListener. Объекты реализации передают измерения экземплярам класса StreamingSensor, вызывая его метод pro cessMeasurement.
И наконец, приведем интерфейс, который соответствует классу Streaming Sensor:
interface StreamingSensorImpl extends SimpleSensorImpl (
/ * *Потоковые сенсоры выдают поток измеренных значений .
*Частота выдачи потока значений не превышает
*заданное количество раз в минуту . @param freq
* Максимальная частота (раз в минуту) выдачи результатов
*измерений данным потоковым сенсором .
*/
public void setSamplingFreguency (int freq)
throws SensorException ;
/ * *
*Данный метод вызывается объектом, представляющим абстракцию
*потокового сенсора таким образом, что этот объект может выполнить обратный вызов к такому Объекту для передачи ему
*измеренных значений .
*@param abst raction Объект абстракции, которому передаются измеренные значения .
* /
public void setStreamingSensorListener (
StreamingSensorListener listener) ;
) / / interface StreamingSensorlmpl
ШАБЛОНЫ ПРОЕКТИРОВАНИЯ, СВЯЗАННЫЕ С ШАБЛОНОМ BRIDGE
Layered Architecture. Шаблон Bridge представляет собой способ организаЦИIt
сущностей (в виде классов), идентифицированных с помощью шаблона Layeгed
Architecture, описанноrо в работе [BMRSS96].
Bгidge _ 239
Abstract Factory. Шаблон Abstract Factory может использоваться шаблоном
Bridge для принятия решения о том, какой класс реализации нужно инстанции рОвзть для объекта абстракции.
раDecorator. Шаблон Decorator может использоваться для динамического выбо
объекта реализации, которому объект абстракции будет делегировать неко торую операцию.
ЭТОТ шаблон ранее был описан в работе [GoF95].
СИНОПСИС
Шаблон Facade упрощает доступ к связанному набору объектов, предоставляя
для связи с этим набором объектов один объект, который используется всеми
другими объектами, не принадлежащими этому набору объектов.
КОНТЕКСТ
Рассмотрим организацию классов, поддерживающих создание и передачу сооб щений электронной почты. Сюда могут входить следующие классы:
• |
мпля |
|
класс MessageBody, экземпляры которого содержат тела сообщений; |
||
• |
ЮJaСС Attachment, экзе |
ры которого содержат прилагаемую к сообщению |
•информацию, которая может быть присоединена к объекту MessageBody; класс MessageHeader, экземпляры которого содержат информацию для за головка - кому, от кого, тема (to, fют, subject) - сообщения электронной
•почты;
класс Message, экземпляры которого связаны с объектом MessageHeader
•и объектом MessageBody;
класс Security, экземпляры которого используются для добавления циф
•ровой подписи в сообщение;
класс MessageSender, экземпляры которого должны отправлять объектЫ
Message на сервер, отвечающий за доставку электронной почты по нужно
му адресу или на другой сервер.
На рис. 7. 1 О представлена диаграмма классов, описывающая отношения меЖдУ
этими и клиентским классом.
Очевидно, что работа с такими классами электронной почты усложняет кли
ентский класс. Чтобы применять эти классы, клиент должен иметь информа
цию как минимум о шести классах, об отношениях меЖдУ ними и о порядке
создания экземпляров таких классов. Если КаЖдый клиент этих классов должен учитывать подобную дополнительную сложность, то многократное использова
ние классов электронной почты весьма затруднено.
Шаблон Facade предоставляет способ защиты клиентов классов, например. классов электронной почты, от всей сложности организации таких классоВ. Этот способ подразумевает наличие дополнительного объекта, который скры-
242 • Глава 7. Структурные шаблоны проектирования
На этой схеме та часть ЮIaсса Client, которая отвечала за взаимодеЙСТВие
склассами электронной почты, теперь объединена в один независимый класс.
иклиентские классы должны знать только о классе MessageCreator. Более того, логика создания всего сообщения, его частей, а также порядка, в котором эти части должны создаваться, сокрыта внутри класса MessageCreator, что избавляет клиентские классы от необходимости знать всю эту информацию.
МОТИВЫ
© МеЖдУ классами, реализующими абстракцию, и соответствующими кли
ентскими классами существует множество зависимостей. Эти зависимости очень усложняют клиентские классы.
@) Нужно упростить клиентские классы, поскольку более простые классы по зволяют делать меньше ошибок. Кроме того, чем проще клиенты, тем тре буются меньшие усилия ДЛЯ использования классов, реализующих абстрак цию, при их изменении.
©Проектируются классы для многоуровневого приложения. Необходимо све сти к минимуму количество классов, доступных с соседних уровней.
РЕШЕНИЕ
На рис. 7. 12 представлена диаграмма классов, демонстрирующая основную структуру шаблона Facade. Объект клиента взаимодействует с объектом Facade, который обеспечивает необходимую функциональность, взаимодействуя с ос тальными объектами. Если лишь некоторые клиенты НУЖдаются в дополни тельной функциональности, то вместо непосредственного предоставления этой функциональности объект Facade предоставляет метод для доступа к другому объекту, который и обеспечивает эту функциональность.
|
|
|
|
|
|
I |
|
|
|
1 |
|
|
I |
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
CLient |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
исПОЛl.зует.... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Facade |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
I |
|
I |
|
|
|
|
I |
|
|
|
1- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
I |
I |
|
|
|
|
|
|
|
|
|
|
I |
|
|
||||||||
|
|
|
|
I |
|
|
|
|
|
|
|
I |
|
|
i |
|
|
|
|
|||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
I |
|
|
|
|
|
|
|
|
|
|
I l - I |
|
|
|
|
I |
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
|
|
J |
|
|
|
|
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
I |
|
I |
|
|
|
J |
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||
|
|
|
|
|
|
|
|
|
РНС. 7.12. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
Шаблон Facade |
|
|
|
|
|
|
|
|
|
|
Facade - 243
eT никакой необходимости в том, чтобы класс Facade являлся непроницаемым Барьером, отделяющим клиентские классы от классов, реализующих абстрак i1li Ю. Вполне достаточно (а иногда и лучще), если класс Facade просто будет i1редставлять собой задаваемый по умолчанию способ доступа к Функциональости классов, реализующих абстракцию. Если некоторые клиенты должныMeTЬ прямой доступ к классу, реализующему абстракцию, то класс Facadeожет иметь метод, который возвращает ссылку на соответствующий объект реализации.
CНазнаТbIx чение класса Facade состоит в том, чтобы разрещить использование про клиентов, а не требовать их в обязательном порядке.
РЕАЛИЗАЦИЯ
Класс Facade должен предоставлять клиентским объектам способ получения прямой ссылки на экземпляр реализующего абстракцию класса, в котором клиентские объекты могут нуждаться. Однако могут существовать такие реали зующие абстракцию классы, о которых клиентские классы не должны ничего знать. Класс Facade обязан скрывать такие классы от клиентских классов. Это можно осуществить следующим образом: такие классы делаются закрытыми
внутренними классами класса Facade.
Иногда нужно изменить классы реализации , используемые объектом-фасадом D.ЛЯ согласования изменений реализуемой абстракции. Например (возвраща ясь к ситуации с электронной почтой, описанной в разделе «Контекст,», могут потребоваться разные наборы классов для создания сообщений, соответст вующих стандартам MIME, МАРI или Notes. Разные наборы классов реализа
ций обычно требуют разных классов Facade . Можно скрыть от клиентских классов факт использования различных классов Facade, применяя щаблон Interface (см. гл. 4): определить интерфейс, который должны реализовывать все классы Facade, участвующие в создании электронной почты. Затем заста
вить клиентские классы обращаться к классу Facade не прямым образом, а че
рез интерфейс.
СЛЕДСТВИЯ |
|
© |
Если поместить класс-фасад между классами, реализующими абстракцию, |
|
и их клиентами, то упростятся клиентские классы, так как зависимости |
|
клиентских классов передадутся классу-фасаду. Клиентам объектов-фаса |
|
дов не нужно знать о каких-либо классах, скрывающихся за классом-фа |
© |
садом. |
Шаблон Facade уменьшает или устраняет связь между клиентским классом |
и реализующими абстракцию классами, поэтому существует возможность изменять классы, реализующие абстракцию, не затрагивая клиентские классы.
244 • Глава 7. Структурные шаблоны проектирования
ПРИМЕНЕНИЕ В JAVA API
в j ava . net класс URL может служить примером шаблона Facade. Он обеспеМО чивает доступ к содержимому ресурсов, на которые указывают URL. Класс жет быть клиентом класса URL и использовать его для получения содержимого URL, не будучи осведомленным о множестве классов, находящихся за фасадданом-, который предоставляется классом URL. С другой стороны, чтобы послать ные на URL, клиент объекта URL может вызвать его метод openConnection, ко торый возвращает объект URLConnection, используемый объектом URL.
ПРИМЕР КОДА
Рассмотрим код для класса MessageCreator, представленноro на рис. 7. 1 1. Экземпляры класса Mes sageCreator используются для создания и отправле ния сообщений электронной почты. Он представлен здесь как типичный при мер класса Facade.
public class MessageCreator
// Константы, обозначающие тип создаваемых сообщений . |
||
public final static int МIМE |
= |
1 ; |
public final static int МAPI |
2 ; |
|
private Hashtaыle headerFields |
= new Hashtaыl( ); ; |
|
private RichText messageBody; |
|
|
private Vector attachments = |
new Vector () ; |
|
private boolean signМessage ; |
|
|
public MessageCreator (String to, |
||
String |
frorn, |
|
String |
subj e c t ) |
this (to, frorn , subject, inferмessageType (to» ; // Constructor (S tring, String, String)
public MessageCreator (String to , String frorn,
|
|
String subject , int |
type) |
|
|
headerFields . put ("to" , |
to) ; |
|
|
|
headerFields . put ("frorn" , frorn) ; |
|
||
|
headerFields . put ("subject" , subject) ; |
|
||
/ * * |
|
Str ing, String , |
int ) |
|
|
/ / Construc tor ( St ring, |
|||
* / |
|
|
|
|
* |
|
Задаем содержимое тела |
сообще ния . |
|
Facade - 245
public void setмessageBody (String messageBody) { |
|
|||
|
setмessaqeBody (new RichTextString (messageBody» |
; |
||
|
// setMessageBody ( S t ring) |
|
||
/ * * |
|
|
|
|
*/ |
Задаем содержимое тела сообщения . |
|
||
* |
|
|
||
public void setмessageBody (RichText messageBody) |
{ |
|||
|
this . messageBody = messageBody; |
|
||
|
// setMessageBody ( RichText) |
|
||
/** |
|
|
|
|
* |
/ |
Добавляем к сообщению присоединяемую информацию . |
||
* |
|
|||
public void addAttachment (Object attachment) |
|
|||
|
attachments . addElement (attachment) ; |
|
||
|
// addAttachment (Obj ect) |
|
||
/** |
|
|
|
|
* |
|
Указываем, |
будет ли сообщение подписано . |
|
*/ |
Значение по |
умолчанию - fals e . |
|
|
* |
|
|
public void setSign= Мessage (boolean signFlag) {
//signМessage signFlag; setSignMessage (boolean)
/**
*
*/Задаем значение для поля заголовка .
public void setHeaderField (String name , String value)
//headerFields . put (name . toLowerCase () , value) ;
/ * *
setHeaderField ( St ring, String)
*
*/Отправляем сообщение .
public void send() {
// send ( )
!46 • Глава 7. Структурные шаблоны проектирования
/**
* Выясняем тип сообщения , исходя из адреса назначения электронной почты .
*/
private static= О ;int inferМessageType (String address) ( int type
return type;
)// inferMessageType ( String)
/** *
*/Создаем объект Secu rity, чтобы подписать это сообщение .
private Security= createSecurity () Security s null ;
/return/ в ; createSecu rity ( )
/**
*Создаем объект Mes sageSende r ,
соответствующий типу отправляемого сообщения .
*/
private void createМessageSender (Message msg) {
}// createMessageSender (Mes sage »
}// c l a s s Mes sageCreator
.llаблон Facade не предъявляет никаких требований к классам, которые
ICпользуются классом Facade. Поскольку они не добавляют ничего нового
информацию о шаблоне Facade, их исходный текст здесь не приводится.
lJАБЛОНЫ nРОЕКТИРОВАНИЯ, СВЯЗАННЫЕ
: ШАБЛОНОМ FACADE
nterface. Можно использовать шаблон lnterface вместе с шаблоном Facade. это
IOзволит применять различные классы фасадов, не требуя от клиентских к.лас
..:овawосведомленности о разных классах.
оС Demeter. Концептуальная модель, применяющая шаблон Law of Demeter
описанный в книге [Grand99]), часто дает начало проекту, который использует uаблон Facade.