![](/user_photo/2706_HbeT2.jpg)
GrandM-Patterns_in_Java
.pdf![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6361x1.jpg)
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6362x1.jpg)
Mediator 8 369
public void registerOkButton (JВutton ok) { okButton = ok ;
/ / registerOkButton ( JButton)
Методы регистрации других объектов GUI более сложны, так как они затраги вают управление специальными событиями ДЛЯ объектов, зарегистрированных
в определенной роли. Управление специальными событиями необходимо ДЛЯ
того, чтобы проверить содержимое отдельных объектов GUI. Следующий ме
тод регистрации более типичен. Он регистрирует поле, предназначенное ДЛЯ
ввода количества участников предстоящего банкета.
public
void registerPeopleCountField (final JТextComponent field) { peopleCountField = field;
DocumentAdapter docAdapter = new DocumentAdapter () {
protected void parseDocument ( ) int count = PEOPLE_COUNТ_DEFAULT; try {
String countText = field. getText () ; count = Integer . parseInt (countText) ; catch (NumberFormatException е) {
if (MIN_PEOPLE<=count
" |
count<=МAX PEOPLE |
|
peopleCount = |
count; |
|
else |
|
|
peopleCount = |
PEOPLE_COUNT_DEFAULT; |
|
} ; ) / / |
pars eDocument ( ) |
Document doc = field . getDocument () ; doc . addDocumentListener (docAdapter) ;
/ / registerPeopleCountField (JTextComponen t )
Этот метод регистрации создает анонимный объект-адаптер, который не про сто вызывает метод enforce l nvariants. Об этом позаботился анонимный
суперкласс-адаптер. Перед тем как вызвать метод enforce l nvariants объекта
BanquetMediator, супеРКJIaСС вызывает свой собственный метод parseDocu rnent. Класс анонимного адаптера его замещает, устанавливая переменную эк
земпляра peopleCount объекта BanquetMediator. Если поле, соответствую Щее количеству человек, намеревающихся посетить банкет, содержит правильное Зliачение, то адаптер это значение записывает в peopleCount. В противном
СЛучае в peopleCount задается специальное значение, информирующее метод enforcelnvariant о том, что в поле количества человек, намеревающихся по
Сетить банкет, введена неправильная величина.
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6363x1.jpg)
370 • Глава 8. Поведенческие шаблоны проектирования
Методы регистрации других текстовых полей работают аналогичным образом.
Они создают объект-адаптер, который проверяет правильность введенного
вполе значения, устанавливает переменную экземпляра в некоторое значеНие
изатем вызывает метод enforce I nvariants.
Метод enforceI nvariants может изменять состояние некоторых компонен
тов GUI, чтобы заставить их удовлетворять некоторым инвариантным оТНоше
ниям. При этом компоненты генерируют события. Объект BanquetMediator
при помощи своих адаптеров получает некоторые из этих событий. Когда ком
понент GUI отвечает на одно из изменений состояния, сделанных методом enforceI nvariants, и передает событие одному из объектов-адаптеров Вап quetMediator, он рекурсивно вызывает метод enforceI nvariants. Чтобы
избежать бесконечной рекурсии, класс BanquetMediator использует флаг,
указывающий на рекурсивные обращения к методу enforce I nvariants.
private boolean busy = false i
private void enforcelnvariants () if (busy)
returni busy = true i
protectedEnforcelnvariants () i busy = false i
/ / enfo rce lnva riants ( )
Как видно, метод enforce Invariants активизирует инвариантные отноше ния непрямым образом. Если он вызывается рекурсивно, происходит немед ленный возврат этого метода. В противном случае он вызывает метод protec t edEn force I nvariants.
Метод enforce Invar iants определяет рекурсивные обращения так: сначала
проверяет, а затем устанавливает значение переменной busy. Поскольку мо
дель управления событием в языке Java гарантирует синхронную передачу со
бытий, метод enforceInvariants не должен быть вызван для управления не
которым событием в то время, как он все еще обрабатывает другое событие.
В подобной ситуации методдолжен быть синхронизирован в соответствии с се
мантикой обрабатываемых им событий.
Приведем инвариантные отношения, активизируемые методом protected
Enforce Invar iants. |
|
• |
Поля Date, Start Time и End Time разрешены тогда и только тогда, когда |
• |
поле Number of People содержит разрешенное значение. |
Если кнопки-переключатели запрещены, их состояние не позволяет их вы |
|
• |
бирать. |
Список блюд доступен тогда и только тогда, когда доступны поля Data, Start |
|
|
Time и End Time и выбран переключатель Buffet (Шведский стол) или ТаЫе |
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6364x1.jpg)
Mediator - 371
(Обслуживание за столиками). Правильное время окончания банкета должно
•быть по крайней мере на один час позднее, чем время начала.
Кнопка ОК доступна тогда и только тогда, когда доступен список блюд и из списка выбрано хотя бы одно блюдо.
private void protectedEnforceInvariants ( )
/ / |
Если задано |
количество человек, переменная enable |
/ / |
должна иметь |
значение t rue . |
boolean enable
=(peopleCount ! = PEOPLE_COUNТ_DEFAULT) ;
/ / |
Поля Data , Start Tirne, |
End Tirne , переключатели Buffet, |
// |
ТаЫе доступны тогда и |
толь ко тогда , когда в поле, |
//предназначенном для количества человек,
// содержится разрешенное значение . dateField. setEnabled (enable) ; startField. setEnabled (enable) ; endField. setEnabled(enable) ; buffetButton . setEnabled(enable) ; tableServiceButton . setEnabled(enable) ;
if (enable) |
{ |
|
|
|||
/ / |
Список блюд доступен тогда и тол ь ко |
тогда , |
||||
/ / |
когда |
поля даты, |
времени или кнопки-переключатели |
|||
/ / |
доступны, и время |
окончания по крайней мере |
||||
/ / |
на один час больше времени начала , |
и выбран |
||||
/ / |
переключатель Bu ffet или ТаЫе . |
|
||||
enable = |
(buffetButton . isSelected () |
|
||||
|
I |
I |
tableServiceButton . isSelected (» |
|
||
|
|
|
|
|
||
foodList . setEnabled(enable |
|
|||||
|
" |
|
endAtLeastOneHourAfterStart (» |
|
||
else |
|
{ |
|
|
|
|
/ / |
Если поля даты или времени или кнопки-переключатели |
|||||
/ / |
недоступны, то список блюд тоже должен быть |
|||||
/ / |
недоступен . |
|
|
|||
foodList . setEnabled(false) ; |
|
|||||
/ / |
Кнопки-переключатели недоступны, поэтому они не |
|||||
/ / |
могут быть выбраны . |
|
||||
buffet8utton . setSelected (false) ; |
|
|||||
tableServiceButton . setSelected (false) ; |
|
|||||
/ / |
Если доступны, то |
|
|
"foodList. qetмinSelectionIndex () >-1) ;
// protectedEnforce lnvariants ( )okButton . setEnabled(foodList . isEnabled()
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6365x1.jpg)
372 • Глава 8. Поведенческие шаблоны проектирования
Классы-посредники часто имеют внугренние вспомогательные методы, кото
рые дополняют логику основного метода активизации инварианта. РазмещеНие некоторой части логики во вспомогательных методах способствует тому, что
размеры основного метода активизации инварианта позволяют легко управлять
им. Следующий метод возвращает true, если поля Date, Start Time и End Time
содержат допустимые значения и время в поле End Time как минимум на один
час больше времени в поле Start Time.
private boolean endAtLeastOneHourAfterStart ( )
Calendar startCalendar = getStartCalendar ( ) ; |
||
if (startCalendar == |
null) |
|
return |
false ; |
= getEndCalendar () ; |
Calendar |
endCalendar |
if (endCalendar == null) return false ;
startCalendar . add (Calendar . MINUTE , 59) ; return getEndCalendar () . after (startCalendar) ;
} / / endAtLeas tOneHourAfterStart ( )
ШАБЛОНЫ ПРОЕКТИРОВАНИЯ, СВЯЗАННЫЕ С ШАБЛОНОМ MEDIATOR
Adapter. Классы Medi ator часто используют объекты-адаптеры для получения извещений об изменении состояния.
Interface. Шаблон Mediator использует шаблон Interface с целью поддержки независимости классов Col league от класса Mediator.
Low Coupling/High Cohesion. Шаблон Mediator - это хороший пример исклю
чения из тех рекомендаций, которые выдаются шаблоном Low Coupling/Нigh
Cohesion (описанным в книге [Grand99]).
Observer. Шаблон Observer представляет собой значительную часть модели де
легирования событий в языке Java. Если необходимо использовать шаблон
Mediator в таком контексте, в котором, по мнению программиста, модель деле
гирования событий в языке Java не может быть использована, то можно ис
пользовать для замены шаблон Observer.
Controller. Шаблон Controller (описанный в книге [Grand99]) позволяет опре
делить, какой объект должен обрабатывать внешнее событие. Шаблон Mediator
помогает реализовать обработку событий.
White Бох Testing. Использование шаблона Mediator приводит в результате
к меньшему количеству ветвей выполнения кода. Это значит, что требуетсЯ
меньше усилий для тестирования программы при помощи шаблона White ВО)(
Testing, описанного в книге [Grand99].
![](/html/2706/346/html_MxkKzTLKJz.Ja4Q/htmlconvd-LkZgZ6367x1.jpg)
37..• Глава 8. Поведенческие шаблоны проектирования
ХОТЯ в игре участвует множество классов, рассмотрим только некоторые ИЗ
них, которые несут обшую ответственность за создание моментальных снимков
состояния игры (рис. 8.14).
|
|
|
|
|
|
использующий |
|
|
|
|
|
|
|
....считывает байты |
|
|
1 : FileInputStream1 |
|||||||||||||||||||||||||||
|
|
|
|
|
|
байты |
|
|
J, |
|
|
|
|
|
|
J, |
|
1 |
|
|
|
|
|
|
|
|
выдающий байты |
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||
|
|
|
|
|
|
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
I |
|
|
|
|
|
|
|
|
|
|
|
||||||||||||
|
|
|
|
|
Использует |
|
|
Deserializer |
|
|
|
|
|
|
I |
FileOutputStreaml |
||||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
|
байты |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
десериализирует.... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
......Записывает |
|
|
использующий |
||||||||||||||||||||
|
--i |
|
|
|
|
|
, |
1 |
|
|
|
|
1 |
J |
|
Serializes |
, 1 |
|
байты в |
|
|
|
|
|
|
|
|
|
|
|||||||||||||||
|
UserInterface |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
"' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||
|
, |
Использует |
|
|
|
|
, выдающий байты |
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||
|
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||
|
|
|
|
|
Использует |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
сериализирует.... |
|
|
|
|
|
|
|
|
|
|
|||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
If |
|
|
|
|
|
|
|
оБыIлIIющийй класс |
||||||||||||||||||||
|
|
|
|
|
|
1 ... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||||||
|
|
|
|
|
|
|
|
, |
|
|
|
|
|
|
|
|
|
|
|
|
|
GameModel |
|
|
|
|
-- |
------ |
---- - |
--- |
,, |
|||||||||||||
|
....Использует |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
- ---- |
|
|
|
|
|
|
|||||||||||||||||||||||||
|
|
|
|
|
createMemento(description:String):MilestoneMementoIF |
|
|
|
|
|
|
|||||||||||||||||||||||||||||||||
|
|
|
|
|
|
setMemento(:MilestoneMementoIF) |
|
|
|
|
|
|
|
|
|
|
||||||||||||||||||||||||||||
|
80сстанавли- ......1 |
|
|
|
|
|
1 |
|
|
|
|
|
|
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||
|
вает состояние |
|
|
Оповещает.... |
|
|
|
|
|
|
|
......Запраwивает создание |
|
|
|
|
|
|
|
|
|
, |
||||||||||||||||||||||
|
из |
Milestone |
|
|
о контрольных |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||
|
Memento |
1 |
|
|
отметках |
|
1 |
|
|
|
|
|
|
|
1 |
|
|
|
|
Milestone Memento |
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||
|
|
|
|
|
MilestoneMementoManager |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
V |
|
|
|
|
|
|||||||||||||||
|
snapshotMilestonе(description:String) |
|
|
|
|
|
|
|
|
|
---- -- - - --- -- - t>1 |
|
|
|
|
|
|
|
||||||||||||||||||||||||||
getMilestoneMementos( ):MilestoneMementoIF |
«interface» |
|
|
|
|
|||||||||||||||||||||||||||||||||||||||
|
|
|
restoreFromMemento(:MilestoneMementoIF) |
- - |
Serializable |
|
|
|
|
|||||||||||||||||||||||||||||||||||
|
|
|
|
|
|
1. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
яВляется.... |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MilestoneMemento - |
|
|
|
|
|
|
. |
м |
|
||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
зто закр |
ытый статический |
|
, |
|
|
|
закрыты |
|
|||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
классом- |
|
, |
|||||||||||||||||
|
|
|
|
0. • * |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
класс-член класса |
|
|
|
|
|
членом |
|
|
||||||||||||||||
|
|
|
|
|
«interface» |
|
|
|
|
<J- |
|
|
|
GameModel |
|
|
|
|
|
|
|
зтого класса |
||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||
|
|
|
|
MilestoneMementoIF |
|
|
--- |
|
--- |
---- -- -------- |
«static» |
|
|
|
|
|
|
|
||||||||||||||||||||||||||
|
|
|
|
|
|
|
- |
|
|
|
- |
|
|
|
|
|
|
|
|
|
|
|
MilestoneMemento l - : |
|||||||||||||||||||||
|
|
|
|
getDescription( ):String |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
Рис. 8.14. |
|
Классы моментального. снимка игры |
' |
|
|
|
|
|
|
|
ОТ |
|||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||
Данные классы принимают участие в двух различных механизмах: |
|
|
|
|||||||||||||||||||||||||||||||||||||||||
• |
сохранения части СОСТОЯНИЯ игры, |
когда герой достигает контрольной |
|
|||||||||||||||||||||||||||||||||||||||||
• |
метки; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
сохранения и восстановления всей игры целиком. |
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||||||||
Классы |
Userl nter face |
И GameModel участвуют в обоих механизмах. |
|
|
|
|
|
Snapshot • 375
UserInterface. Все предпринимаемые игроком действия проходят через класс
User lnterface.
Класс Userlnterface передает большую часть действий, инициируемых игро ком, экземпляру класса GameModel . Однако в процессе работы с инициируе мыми игроком моментальными снимками игры задействованы и другие подхо ды, которые будут рассмотрены ниже.
GameModel. Класс GameModel отвечает за поддержание состояния программы во время сеанса игры. Класс Userlnterface оповещает экземпляр класса GameMode l , если игрок делает что-то связанное с игрой. Экземпляр класса GameModel определяет последствия этого действия, соответствующим образом изменяет состояние игры и оповещает пользовательский интерфейс. Кроме того, экземпляр класса GameModel может сам инициировать некоторые дейст
вия. Он всегда сообщает о последствиях любого инициированного им действия пользовательскому интерфейсу, но не всегда - о самом действии.
Участие класса Userlnterface в процессе создания моментального снимка состоит в том, что он инициирует один вид моментального снимка и оба вида
восстановления. Класс GameModel отвечает за состояние игры, поэтому он дол жен участвовать в любой операции, манипулирующей состоянием игры.
Опишем другие классы и интерфейсы, принимающие участие в сохранении и восстановлении частичного состояния.
MilestoneMemento. Класс Mi lestoneMemento - это закрытый класс, опреде
ляемый классом GameModel . Объект GameMode l создает экземпляры класса Mi lestoneMemento, содержащие копии значений, которые определяют сохра няемое частичное состояние. Имея объект MilestoneMemento, объект GameModel может восстановить свое предьшущее состояние, содержащееся в объекте
Mi lestoneMemento.
MilestoneMementoIF. Этот интерфейс является открытым и реализуется клас сом Miles toneMemento. За пределами класса GameModel доступ к экземпля
рам класса MilestoneMemento может быть осуществлен только как к экземп
лярам класса Obj ect или через интерфейс Mi lestoneMementoIF. Ни один режим доступа не позволяет объекту обращаться к информации о состоянии,
инкапсулированной в объектах Mi lestoneMemento.
МilestoneMementoManager. Класс MilestoneMementoManager вносит свой вклад
в процесс принятия решения о создании объектов MilestoneMemento. Он так
Же управляет их использованием после того, как они были созданы.
Приведем описание записи частичного состояния игры, происходящего после i1o. ro, как управляемый игроком герой достиг контрольной метки.
2.Существует объект MilestoneMementoManager, связанный с каждым объек том GameMode l . Когда объект GameMode l принимает состояние, соответст-
376 • Глава 8. Поведенческие шаблоны проектирования
вующее моменту достижения контрольной отметки, он вызывает метод s napshotMilestone связанного с ним объекта MilestoneMementoManager.
Метод snapshotMiles tone передает методу строку, в которой содержится описание контрольной метки. Управляемый игроком герой мог ранее уЖе быть у этой контрольной метки, умереть и затем возвратиться к предьщу_ щей контрольной метке. Если объект MilestoneMemento для некоторой контрольной метки уже существует, то для этой контрольной метки не дол жен создаваться другой объект Mi les toneMemento.
З. Объект Mi les toneMementoManager определяет, существует ли уже объект Miles toneMemento для контрольной отметки, сравнивая строку описания, переданную его методу snapshotMi lestone, с описаниями уже сушест
вующих объектов MilestoneMemento. Если объект MilestoneMemento
с данным описанием уже существует, то метод snapshotMi les tone не предпринимает никаких дополнительных действий.
4.Если объект Miles toneMementoManager определяет, что для контрольной
отметки еще не сушествует объект MilestoneMemen to, то объект МНе stoneMementoManager инициирует создание объекта Mi lestoneMemento
ДЛЯ записи частичного состояния игры в данный момент. При этом он вы зывает метод createMemento объекта GameMode l, передавая ему то же са мое описание, которое он передавал объекту Miles toneMementoManager.
5.Метод createMemento возвращает вновь созданный объект Miles tone Memento, который объект MilestoneMementoManager добавляет в свою
коллекцию объектов Mi lestoneMementoIF.
Если руководимый игроком герой умирает, объект UserI nterface предлагает игроку снова включиться в игру не с самого начала, а с последней пройденной
контрольной отметки. Он предлагает игроку сделать выбор из списка коюроль |
|||||
HbIX |
отметок, |
вызывая метод getMi lestoneMementos объекта Mi les tone |
|||
то |
|
составляет |
|
|
|
MementoManager. Этот метод возвращает массив объектов Mi lestoneMemento, |
|||||
ко рый |
|
|
коллекциюсобранную, |
объектом MilestoneMementoManager . |
Если игрок указывает, что он хочет, чтобы герой возобновил игру от одной из
ранее ПРОЙденных контрольных отметок, объект User Interface передает со
ответствующий объект MilestoneMemento методу restoreFromМemento объ екта MilestoneMementoManager. Этот метод в свою очередь вызывает метоД setMement o объекта GameMode l, передавая ему выбранный объект МНе
s toneMemento. Объект GameModel восстанавливает свое состояние, используя
информацию, находящуюся в этом объекте MilestoneMemento.
При использовании другого механизма моментального снимка в файле сохра
няется полное состояние игры, включая объект Mi lestoneMementoManager
и его коллекцию объектов Mi lestoneMemento. Этот механизм основан на
средстве сериализации языка Java.
В процессе сохранения (восстановления) в файл (из файла) моментальноГО снимка полного состояния игры участвуют следующие классы.