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

GrandM-Patterns_in_Java

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

Balking 469

1 . НемедЛенный запуск новой ВОДЯНОЙ струи. Запуск новой струи в тот момент, когда одна водяная струя уже приведена в действие, приводит к такому же эффекту, что и более продолжительное по сравнению с нормальным дейст­ вие уже существующей водяной струи. ОптимальнаядЛительность нормаль­ ной струи должна быть определена экспериментально. Более продолжи­ тельная водяная струя может привести к излищнему расходу воды, поэтому этот вариант не очень хорош.

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

3.Ничего не делать. Этот вариант не предусматривает излищнего расхода воды, поэтому он является наилучшим.

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

другого.

Предположим, что обращение к методу объекта производится в тот момент, когда состояние объекта не позволяет ему правильно выполнить метод. Если управление ситуацией таково, что метод завершается, не выполнив свою задачу, значит, была произведена отмена метода. В UML нет стандартного способа, позволяющего обозначить метод, вызов которого сопровождается его отменой.

вВ данной книге вызов метода, сопровождающегося отменой, обозначается

виде стрелки, изогнутой в обратном направлении.

На рис. 9. ] 5 представлено такое поведение метода flush класса Flusher.

[ :LightSensor

 

 

 

 

 

 

 

 

1A:flush()

 

 

 

 

18 :fl.ushO

 

 

 

 

 

 

:Flush8otton

Рис. 9.15.

Взаимодействие ДПЯ

класса Flusher

 

 

 

 

МОТИВЫ

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

©Задержка выполнения вызова метода до тех пор, пока состояние объекта не

станет подходящим, - это неприемлемая политика при рещении данной

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

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

опасных последствий.

470

Глава 9. Шаблоны проектирования для конкурирующих операций

РЕШЕНИЕ

Диаграмма взаимодействия, представленная на рис. 9. 16, включает объекты, сотрудничаюшие в рамках шаблона Balking.

Объект C l ient вызывает метод doI t объекта Service. Изогнутая в обратном

направлении стрелка1 указывает на тосе, что может быть произведена отмена ме­

тода. Если метод do t объекта Se rvi вызывается в тот момент, когда состоя­ ние объекта Service не позволяет выполнить обрашение к его методу dolt, то

этот метод возвращается, не выполнив свои обычные функции.

Метод dol t возвращает результат, обозначенный на диаграмме как didIt.

Этот результат может иметь значение true или false в зависимости от того, вы­ полнил ли он свои обычные функции или бьmа произведена отмена метода.

l:didIt:-dоIt()

Рис. 9.16. Взаимодействие, демонстрирующее отмену метода

РЕАЛИЗАЦИЯ

Если можно выполнить отмену eToдa, то прежде всего он, как правило, прове­ ряет состояние объекта, которому он принадлежит, с целью определения, дол­ жен ли он быть выполнен.

Когда метод объекта выполняется, решив, что не будетдляотменен, недопустимо, чтобы состояние объекта стало вдруг неприемлемым выполнения этого ме­

тода. Чтобы зашититься от подобной несогласованности, можно использовать

шаблон Single Threaded Execution.

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

вом возврата некоторого значения, метод может также известить их о том, что

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

ции. Если вызывающую сторону не интересует, была ли произведена отмена

метода, он может не возврашать такую информацию. СЛЕДСТВИЯ

© Обращения к методам не будут выполнены, если они производятся в тот

момент, когда состояние объектов не позволяет это сделать.

Обращение к методу, который можно было отменить, означает, что метоД

 

может не выполнить свои обычные функции и при этом вообще ничего не

 

сделать.

Balking 8 471

ПРИМЕР КОДА

Приведем код для класса Flusher, рассмотренного в разделе « Контекст» :

public class Flusher (

private boolean flushInProgress = falsei

/* *

* Этот метод вызывается для запуска водяной струи .

* /

public voia flush ( ) ( synchronizea (this )

i f ( flushInProgress) return i

flushInProgress = true i

// Здесь должен

быть код для

активизации водяной струи .

/ * *

*

Этот метод вызывается с той целью,

чтобы известить

*

данный объект о завершении действия

водяной струи .

* /

voia flushCompletea ( ) { flushInProgress = falsei

}// f lushCompleted ( )

// class Flusher

Если метод flush вызывается в тот момент, когда водяная струя уже действует,

будет произведена отмена этого метода.

Обратите внимание, что в методе flush использован оператор синхронизации.

Его присутствие объясняется тем, что, если многочисленные обращения к ме­

тоду fl ush происходят одновременно, результат будет ожидаемым. Только Один вызов будет выполняться нормально, а другие будут отменены. Если бы

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

ли бы выполняться нормально в один и тот же момент времени.

Также следует заметить, что метод flushCompleted не синхронизирован. Это

объясняется тем, что присваивание значения false переменной flushI nPro­ gress никогда не приведет к появлению проблемы. Поскольку метод f l ush

Completed не изменяет никакую другую информацию о состоянии, парал­

лельные обращения к методу fl ushCompleted вполне безопасны. Кроме

472

Глава 9. Шаблоны проектирования для конкурирующих операций

того, не может быть параллельных обращений к методу flushCompleted, по­

скольку устройство механизма смывного устройства таково, что оно ФИзиче­

ски не способно активизировать два водяных потока одновременно.

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

С ШАБЛОНОМ BALKING

Guarded Suspension. Шаблон Guarded Suspension предоставляет альтернативный

способ управления обращениями к методам объектов, состояние которых не

позволяет выполнить эти обращения.

Single Тhreaded Execution. Шаблон Balking часто используется вместе с шабло­ ном Single Threaded Execution для согласования изменений состояния объекта.

Этот шаблон основан на материале, представленном в работе [Lea97].

СИНОПСИС

Управляет порядком, в соответствии с которым потокам предстоит выполнить последовательный код, используя для этой цели объект, который явным обра­ зом задает последовательность ожидающих потоков. Шаблон Scheduler обеспе­ чивает механизм реализации политики планирования, но при этом не зависит ни от одной конкретной политики.

КОНТЕКСТ

Предположим, проектируется ПО ДЛЯ управления физической безопасностью зданий. Система безопасности должна включать контрольные пункты. Прежде чем пройти через такой пункт, человек должен провести идентификационной карточкой через сканер. При этом контрольный пункт либо разрешает человеку пройти, либо нет. В любом случае: прошел ли человек через контрольный пункт, или его карточка не была принята - входные данные будут распечатаны вжурнале регистрации, находящемся в центральном офисе службы безопасности.

Взаимодействия на рис. 9.17 включают объекты Securi tyCheckpoint, которые создают объекты Journa lEntry и передают их методу print объекта Printer. Несмотря на простотудиаграммы, с этой структурой связана одна проблема. Она возникает в том случае, когда люди проходят через три или более пропускных

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

пись регистрации, другие обращения к принтеру находятся в состоянии ожида­

ния. После окончания распечатки первой регистрационной записи неизвестно,

какая запись будет распечатана следующей. Это означает, что записи регистра­

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

h kpoin

t-------'- ---"'-------"

1._____ __....J

 

---+

 

 

 

 

 

1 :рп пЦentry) {guarded}

 

 

Р

:SecurityC ec t

 

:

d t

 

п _е r

1 1:entry:..createo

entrv:Journa {new}

lEntryзаимод ствие АЛЯ ж рнала с стем безо

Рис. 9.17. В ей у и ы пасности

474 Глава 9. Шаблоны проектирования ДЛЯ конкурирующих операций

Чтобы записи в журнале распечатывались в порядке их фактического ПОСТУпле_

ния, можно просто помещать каждую журнальную запись в очередь и затем

распечатывать журнальные записи в том порядке, в котором они заносились

в очередь. Хотя здесь все еще возможно одновременное поступление трех или

более журнальных записей, вероятность такой ситуации значительно СНИжает_

ся. Для распечатки журнальной записи может потребоваться одна сеКУнда.

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

поступили в течение этого промежутка времени. Помещение журналЬной запи­

си в очередь может потребовать всего лишь примерно одной микросекунды.

При этом вероятность нарушения порядка распечатки журнальных записей

уменьшается в миллион раз.

Класс Printer мог бы отвечать за организацию очереди журнальных записей,

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

которая обладает большим потенциалом с точки зрения многократного ис­

пользования, если она реализуется как отдельный класс. Представленная на рис. 9. 18 диаграмма взаимодействия демонстрирует, как объект принтера мо­ жет взаимодействовать с другими объектами, организуя очередь на выполнение обращений к его методу print.

,.-------:SecurityCheckp1

 

2:

 

oint

рппt(епtry)

 

 

l:create()1

entry:JoцrnalEntry

Этот пор, ему

1 2.1:enter(entry)

2.2:done() 1

метод не возвратится до тех

 

пока Scheduler не разрешит

 

это сделать.

 

Рис. 9.18. Журнал системы безопасности, использующий объект-планировщик

Объект SecurityCheckpo int вызывает метод print объекта printer. Метод print начинается с обращения к методу enter объекта Scheduler. Метод enter не заканчивает свою работу до тех пор, пока объект Schedu ler не разре­

шит ему это сделать. Когда метод print заканчивает свою работу, он вызывает

метод done объекта Scheduler. В промежутке времени между возвратом мето­

да enter И вызовом метода done объект Scheduler полагает, что управляемый

им ресурс занят. Ни одно из обрашений к его методу enter не будет выполне­

но, пока объект Scheduler считает, что управляемый им ресурс занят. Это га­

рантирует, что в некоторый момент времени только один поток выполняет ту часть метода print, которая начинается с его обращения к методу enter объ­

екта Scheduler и заканчивается его обращением к методу done объекта

Scheduler.

Если объект Scheduler не ожидает обращения к своему методу done, то вызов его метода enter будет выполнен немедленно. Затем объект Sche­

Scheduler 475

Реальная логика выполнения, согласно которой объект Schedu ler принимает решение, когда должен выполниться вызов метода enter, инкапсулирована

в объекте Scheduler. Это позволяет менять логику, не затрагивая другие объ­ екты. В данном примере, когда несколько обращений к методу enter ожидают

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

duler будет ожидать вызова своего метода done .

Если объект Scheduler ожидает обращения к своему методу done, то вызов его метода enter будет ждать своего выполнения до тех пор, пока не про­ изойдет вызов метода done объекта Scheduler. Если при вызове метода done объекта Scheduler имеются какие-либо обращения к его методу еn te r, ожидающие выполнения, то для выполнения будет выбрано одно из

таких обращений к методу enter.

Если своего выполнения ожидают несколько обращений к методу enter объекта Schedu ler, то объект Scheduler должен выбрать следующий вы­ зов метода enter, которому будет разрешено выполниться. Он выберет тот, который был передан объекту JournalEntry раньше всего. Если несколько объектов JournalEntry имеют одинаковое время поступления, то один из них будет выбран произвольно.

Чтобы класс Scheduler мог сравнивать время создания объектов Journal ­ Entry и оставаться при этом независимым от класса Journal Entry, он не дол­ жен прямо ссьшаться на класс JournalEntry. Он может ссылаться на класс Journa lEntry через интерфейс (рис. 9. 19).

 

 

 

 

 

 

*

 

 

 

 

 

 

 

 

 

 

 

 

«interface»

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ScheduleOrdering

 

 

 

 

 

 

 

 

 

 

....

 

scheduleBefore(:ScheduleOrdering):boolean

 

 

 

 

 

 

 

 

 

 

Планирует обработку

 

 

 

 

 

 

 

 

 

06'ЬеКТОВ

ScheduleOrdering

*

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

Распечатывает

 

 

 

 

 

1

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

I JournalEntry

*

 

 

 

I

Scheduler

I

 

 

 

 

 

 

 

 

Соэдает....*

 

 

 

 

 

 

 

 

 

 

1

 

....Планирует распечатку

1

 

 

 

 

 

 

1

 

 

 

 

1

 

 

журнальных записей

I SecurityCheckpoint

 

 

Испольэует

 

 

 

 

 

 

 

 

 

регистрации

 

*

1

 

 

 

 

Printer

I

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 9.19. Классы планирования регистрационных записей в журнале

I<.ласс Schedu ler ничего не знает о классе JournalEnt ry. Он просто плани­

Рует обработку объектов, реализующих интерфейс ScheduleOrdering. Этот

интерфейс объявляет метод scheduleBefore, который вызывается классом

476

Глава 9. Шаблоны проектирования ДЛЯ конкурирующих операций

Scheduler С целью определения, какой из двух объектов ScheduleOrdering

должен быть обработан первым. Хотя класс Scheduler инкапсулирует ПОЛИти

ку управления, позволяющую определять, когда объекту ScheduleOrdering

будет дано разрешение на обработку, он делегирует принятие решения, касаю

шееся последовательности обработки, объекту Schedul eOrdering.

МОТИВЫ

©Несколько потоков могут потребовать доступа к ресурсу одновременно,

итолько один поток в какой-то момент времени может осуществить доступ

кресурсу. дoc

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

РЕШЕНИЕ

Шаблон Sclledu1er использует некоторый объект, чтобы явным образом управлять параллельными запросами с целью их непараллельной обработки. На рис. 9.20 показаны классы и интерфейс в шаблоне Scheduler.

 

 

 

 

*

 

 

 

 

 

 

 

 

 

 

 

«;"terface»

 

 

 

 

 

 

 

Планирует обработку

 

ScheduleOrderi"9

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

объектов ScheduleOrderlng

scheduleBefore(:ScheduleOrderi"9):boolea"

 

 

 

 

1

 

 

А

 

 

 

 

 

I Scheduler

I

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

1

 

 

 

АЛЯ

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

1

 

 

 

 

 

I

 

 

 

 

 

 

 

 

Планирует объекты

 

I

 

 

 

 

 

 

 

 

 

I

 

Обрабатывает

 

 

 

 

 

 

 

Request

 

обработки

 

I

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Request

 

 

 

 

 

 

 

 

 

 

 

 

l

 

 

 

 

 

Processor

I

 

 

 

 

1 *

 

1

 

 

 

 

 

 

 

'1

 

 

 

 

 

 

Рис. 9.20. Классы шаблона Scheduler

Опишем роли, исполняемые этими классами и интерфейсом.

Request. Выступающие в этой роли классы должны реализовывать интерфейс,

исполняющий роль ScheduleOrdering. Объекты Request инкапсулируют за

прос к объекту Proces sor на выполнение каких либо действий.

Processor. Экземпляры классов в этой роли выполняют вычисление, описанное

в объекте Reque st. Экземпляры классов могут быть представлены нескольКИ ми объектами Reques t, но они могут выполнить только одну операцию, пред

ставленную объектом Request, в некоторый момент времени. Объект p roces : sor делегирует объекту Scheduler ответственность за управление обрабоТКОIi

объектов Request. В какой то момент должен обрабатываться только одИК

объект.

s chedu leBefore.

Scheduler - 477

Scheduler. Экземпляры классов в этой роли управляют обработкой объектов Reques t, выполняемой объектом Proces sor. Чтобы быть независимыми от типов запросов, класс Schedu ler не должен ничего знать об управляемом им

классе Request. Вместо этого он осуществляет доступ к объектам Reques t че­ рез реализуемый ими интерфейс ScheduleOrder ing.

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

гирует эту ответственность интерфейсу ScheduleOrder ing.

ScheduleOrdering. Объекты Request реализуют интерфейс, который выполняет эту роль. Выступающие в этой роли интерфейсы предназначены для решения задач двух типов.

1 . Ссылаясь на интерфейс Schedu leOrder ing, классы Proces sor не зависят от класса Reques t .

2. Вызывая методы, определяемые интерфейсом S chedul eOrderi ng, классы Schedu ler способны делегировать принятие решения о том, какой объект Request будет обработан следующим. Тем самым достигается независи­ мость- от типов решаемых задач классами Schedu ler. На рис. 9.20 такой ме­ тод

Взаимодействие между объектом Processor и объектом Scheduler происхо­ дит в два этапа (рис. 9.21). Оно начинается с обращения к методу do It объекта Processor. Метод doI t вызывает метод enter объекта Schedu ler, связанного

с объектом Processor . Если в данный момент никакой другой поток не вы­

полняет остальную часть метода doI t , то метод enter выполняется немедлен­ но. После выполнения метода enter объект Scheduler знает, что управляе­ мый им ресурс занят. Когда ресурс занят, не будет выполнен ни один вызов метода enter объекта Scheduler до тех пор, пока ресурс не освободится и объ­ ект Scheduler не придет к решению, что подошла очередь выполнить очеред­

ной запрос.

 

 

--+

 

 

 

 

 

 

 

 

 

1: dolt(r)

 

 

 

 

 

 

 

 

 

 

 

:Processor

 

 

 

 

 

 

 

 

 

 

 

 

 

1.2:done() 1

 

 

 

 

 

 

 

 

 

Этот метод не выполнится до тех

 

 

 

 

 

пор, пока Scheduler не

разрешит

 

 

:Scheduler

 

 

выполнение.

 

 

 

 

 

 

 

 

 

 

11.1.: scheduleBefOre(:ReQuest),...--''--_-,

 

 

 

 

 

 

 

 

r:Reguest

 

Рнс. 9.21.

Взаимодействие для Scheduler

478

Глава 9. Шаблоны проектирования дпя конкурирующих операций

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

будет вызван метод done объекта Scheduler. Когда один поток обращается

к методу done объекта Scheduler и какие-либо другие потоки ожидают выпол­

нения метода enter объекта Scheduler, тогда один из них будет выбран дЛя

выполнения.

Если вызов метода enter объекта Scheduler должен ожидать своего выполне_ ния и имеются другие вызовы, ожидающие выполнения метода enter, то объ­ ект Scheduler должен решить, какой вызов будет выполнен на этот раз. При­ нятие решения он делегирует объектам Request, которые были переданы этим методам в качестве параметров с целью определения, какой вызов будет выпол­ нен следующим. Объект Scheduler делает это через вызов методов, объявлен­

HblXных интерфейсом ScheduleOrdering специально для этой цели и реализован­

объектом Request .

РЕАЛИЗАЦИЯ

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

собъектами Request с целью определения порядка выполнения обращений

кего методу enter. Примером такой политики может служить поведение, при котором разрешенный порядок выполнения обращений к методам enter соот­ ветствует порядку их вызова. В таких случаях нет необходимости передавать объекты Request методу enter ИЛИ создавать интерфейс ScheduleOrdering.

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

СЛЕДСТВИЯ

© Шаблон Scheduler предоставляет способ явного контроля в такой ситуации, когда потоки могут выполнять код.

@) Политика планирования инкапсулирована в своем собственном классе

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

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

ПРИМЕР КОДА

Приведем код, реализующий проект планирования вывода на печать, рае:

смотренный в разделе .Контекст». В первом листинге - реализация клас<i3

Printer, управляющего распечаткой записей журнала контрольного пункfI1

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

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