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

GrandM-Patterns_in_Java

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

420

Глава

8.

Поведенческие шаблоны проектирования

 

 

 

 

* связанной с датами,

которые отображаются .

 

 

* /

 

 

 

 

 

 

private class DateCache (

 

 

private Date date;

 

 

 

private String[ ] holidayStrings ;

 

 

DateCache (Date

dt)

{

 

 

date = dt ;

== null) {

 

 

 

if

(holiday

 

 

 

 

holidayStrings = holiday . NO_HOLIDAY ;

 

 

 

 

else (

 

= holiday . getHolidays (date) ;

 

 

 

 

holidayStrings

/ / i f

// constructo r ( Dat e )

//c lass DateCache

//c l a s s CalendarDisplay

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

В шаблоне Strategy в роли ConcreteStrategy выступают разные подклассы

класса Hol iday. Они не представляют особого интереса при рассмотрении

шаблона Strategy и имеют следующую базовую структуру:

public class USHoliday implements HolidaySetIF ( public String [ ] getHolidays= (Date dt) (

String [ ] holidays HolidaySetIF .NO_HOLIDAYi

return holidays ;

// getHolidays ( Date )

// c l a s s USHoliday

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

Adapter. С точки зрения структуры шаблон Adapter аналогичен шаблону Strategy.

Отличие заключается в его предназначении. Шаблон Adapter позволяет объекту

Cl ient выполнять свою изначально предопределенную функцию, вызывая ме­

тод объектов, реализующих определенный интерфейс. Шаблон Strategy предос-

Strategy 421

тавляет объекты, реализующие определенный интерфейс, с uелью изменения или определения поведения объекта C l ient.

Flyweight. При наличии множества клиентских объектов лучше всего реализо­ вывать объекты в роли ConcreteStrategy как объекты Flyweight.

Null Object. Шаблон Strategy часто используется вместе с шаблоном Null

Object.

Template Method. Шаблон Template Method управляет альтернативными вари­ антами поведения не при помощи делегирования, а посредством создания под­

классов.

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

СИНОПСИС

Создается абстрактный класс, содержащий только часть логики, необходимой

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

кретные методы вызывают абстрактный метод, в котором должна находиться

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

КОНТЕКСТ

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

дующие требования:

возможность для пользователя ввести свои идентификатор и пароль;

аутентифицировать ID пользователя и пароль, результатом чего должен

быть объект. Если при аутентификации создается некоторая информация, которая в дальнейшем понадобится как подтверждение аутентификации, то получаемый в ходе аутентификации объект должен инкапсулировать эту

информацию;

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

няющееся (возможно анимационное) изображение, которое информирует

пользователя о выполнении аутентификации и о том, что все идет нормально;уведомить остальную часть приложения или апплета о том, что вход в сис­сле

тему завершен, и с

елать объект, создаваемый в ходе операции аутентифИ­

кации, доступным

для остальной части приложения.

Возможность ввода информации для пользователя и уведомление пользователЯ

о выполняемой аутентификации не зависят от приложения. Хотя видимые

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

ложений, основаны они всегда на одной и той же логике.

Аутентификация пользователя и оповещение остальной части приложения за­

висят от приложения. При решении этих задач каждое приложение или апплет

будет предоставлять свою собственную логику.

Способ организации класса Logon в значительной степени зависит от того, на­ сколько удобно будет его использовать разработчикам. Очень гибкий механизМ

Template Method 8 423

представляет собой делегирование. Можно организовать класс Logon таким образом, что он будет просто делегировать аутентификацию пользователя и оповещение остальной части приложения. Хотя такой подход предоставляет программисту большую свободу, он не способствует принятию им правильного решенияl.

Программмисты, скорее всего, нечасто будут использовать ваш класс Logon.

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

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

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

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

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

На рис. 8.29 представлена диаграмма, демонстрирующая такую организацию

класса Logon и его подклассов.

AbstradLogon

LogonO

..,

#authenticate{userIO:String, password:String) :Objed #noti.fyAuthenticated{authentijicationToken:Objed)

. . .

t

Logon #authenticate(userID:String, password:String):Object

#пotifyAuthenticated(authentificationToken:Object)

Рис. 8.29. Класс Logon и его подклассы

Класс Abst ractLogon имеет метод под названием logon, содержащий общую

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

грамму. Он вызывает абстрактные методы authenticate и noti fyAuthenti ­ cation для выполнения зависящих от программы заданий по аутентификации пользователя и оповещения остальной части программы о выполненной аутен­ тификации.

в действительности(Примсамеч.поредсебе.) подход не определяет правильность или неправиль­

ность решения.

424

Глава

8.

Поведенческие шаблоны

проек

ти

рования

 

 

 

 

МОТИВЫ

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

во множестве программ.

©Общая структура поведения класса всегда будет одной и той же дЛЯ всех

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

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

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

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

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

РЕШЕНИЕ

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

На рис. 8 .30 представлена диаграмма классов, которая демонстрирует органи­

зацию шаблона Template Method.

Рассмотрим роли, исполняемые классами в этом шаблоне.

AЬstractTemplate. Класс, выступающий в этой роли, имеет конкретный ме­

тод - temp l ateMethod, который содержит общую логику данного класса. ОН

AbstractTemp/ate

templateMethodO

. . .

#орегаНоnl

#орегаНоn2

.. .

t

ConcreteTemplate

#operationl

#operation2

Рис. 8.30. Шаблон Template Method

Template Method _ 425

вызывает другие методы, объявленные в классе AbstractTempl ate как абст­ рактные, для активизации логики, которая различна для каждого подкласса класса AbstractTemp late.

ConcreteTemplate. Класс в этой роли представляет собой конкреТНblЙ подкласс класса AbstractTemplate. В нем замещаются абстраКТНblе методы, объяв­ леННblе его суперклассом, с целью предоставления логики, необходимой для завершения логики метода templateMethod.

РЕАЛИЗАЦИЯ

Класс AbstractTempl ate обеспечивает руководство, согласно которому про­ киграммист обязан заместить абстраКТНblе метоДЬ! с целью предоставления логи­

для заполнения пробелов логики Template Method. Можно дополнить струк­

туру, объявляя в подклассах дополнитеЛЬНblе методы, предназначеННblе для замещения и обеспечивающие дополнительную или необязательную логику.

В качестве примера рассмотрим класс под названием Paragraph, представляю­

ЩИЙ абзаЦbl в документе текстового процессора.

Одна из обязанностей класса Paragraph заключается в том, что он должен оп­ ределять, как заполнять строки содержащимися в них словами, и при этом ос­ таваться В пределах задаННblХ полей. Класс Paragraph имеет метод, КОТОРblЙ отвечает за заполнение словами абзаuа. Некоторые текстовые проuеССОрbl до­ пускают обтекание рисунков словами, поэтому класс Paragraph определяет абстраКТНblЙ метод, КОТОРblЙ ВblЗblвается логикой переноса слов класса с целью определения полей для строки текста. Конкретные подклаССbl класса абзаuа вынуждеНbI обеспечивать реализацию этого метода с целью определения полей lU1я каждой строки.

Некоторые текстовые процеССОрbl включают механизм переноса слов, который автоматически определяет то место, где слова должны бblТЬ разделеНbI для пе­

реноса. Эта характеристика позволяет переносить болееДЛИННblе слова с одной

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

ну. Поскольку не каЖДblЙ теКСТОВblЙ процессор будет требовать от класса

Paragraph поддержку переноса слов, для этого класса нет СМblсла определять

абстрактный метод переноса слов и заставлять подклассы замещать его. Однако

бьuIO бbl неплохо, если бbl в классе Paragraph бblЛ бbl объявлен пустой метод lU1я переноса слов, Вblзываемый логикой переноса слов. Такой метод нужно объявлять для того, чтобbl подклаССbl класса Paragraph замещали этот метод

втех случаях, когда нужна поддержка переноса слов.

ПодоБНblе методы, которые могут бblТЬ произвольно замещены с целью пре­

доставления дополнительной или специальной функциональности, называют­ ся hook-меmоаамu. Чтобbl программист мог знать о hооk-методах, предостав­

ЛяеМblХ классом, можно применить к hооk-методам соглащение об именах. Два

самых распространенных соглашения, касающиеся имен ДЛЯ hооk-методов, за­ l<.Лючаются в том, что они либо начинаются с приставки do-, либо заканчива-

426

Глава

8.

Поведенческие шаблоны проект

ирования

 

 

 

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

нах, метод переноса слов класса Paragraph может носить имя doHyphenation

или hyphenationHook.

СЛЕДСТВИЕ

Программист, который пишет подкласс класса AЬs t ractTemplate, вынужден кизамещать те методы, которые должны бьпь замещены с целью завершения логи­ суперкласса. Оптимально спроектированный класс TemplateMethod обла­ дает такой структурой, которая предоставляет программисту руководство по соз­

данию основной структуры подклассов класса AЬs tractTempl ate.

ПРИМЕР КОДА

Приведем код, который реализует проект, описанный в разделе «Контекст». Сначала - код для класса AЬstractLogon. В шаблоне Template Method он иг­ рает роль AЬstractTemplate. Его метод шаблона называется logon. Метод logon активизирует диалоговое окно, которое предлагает пользователю ввести его идентификатор и пароль. После того как пользователь ввел ID и пароль, метод logon отображает окно, которое сообщает пользователю, что идет аутен­ тификация. Это окно остается во время обращения метода l ogon к абстрактно­ му методу authenticate для аутентификации ID пользователя и пароля. Если аутентификация прошла успешно, то диалоговые окна пропадают и вызывается абстрактный метод noti fyAuthentication, чтобы известить остальные части программы о завершении аутентификации пользователя.

public abstract class AbstractLogon (

/ * *

*Этот метод аутентифицирует пользователя .

*@param frame

* Родительское окно диалогов , которые выводит на экран

*этот метод .

*@param programName Имя программы .

*/

public void logon (Frame frame , String programName ) Object authenticationToken ;

LogonDialog logonDialog; logonDialog = new LogonDialog (frame ,

"Log оп to "+programName) ;

JDialog waitDialog а createWaitDialog (frame) ;

Класс LogonDi alog реализует диалог, напоминающий пользователю о вводе

информации для входа. Переменная wai tDialog ссылается на окно, содержа­

щее сообщение ДЛЯ пользователя, аутентификация которого выполняется.

Templote Method 8 427

"ЬНе (true)

(

 

waitDialog. setVisible (false) ;

logonDialog . setVisible (trUe) i

waitDialog. setVisible (true) i

try (

 

 

 

String userID = logonDialog . getUserID ( ) ;

 

String password = logonDialog . getPassword () ;

 

authenticationToken = authenticate (userID ,

 

password) i

 

 

break ;

 

}

catch

(Exception е)

(

 

/ / Сообщает поль зователю, что аутентификация

 

// закончилась неудачей .

 

JOptionPane . showМessageDialog (frame ,

 

е . getмessage () ,

 

 

"Authentication

Failure" ,

 

JOptionPane . ERROR_МESSAGE)

}

/ / try

 

 

/ / Аутентификация прошла успешно .

waitDialog. setVisible (false) ;

logonDialog . setVisible (false) i

notifyAuthentication (authenticationToken) ;

/ / l ogon ( )

 

 

Остальная часть этого листинга простоИдемонстрирует абстрактные методы,

определяемые в классе AbstractLogon вызываемые методом logon.

/ * *

 

*

Аутентифицирует пользователя , исходя

из предоставленных

*

I D поль зователя и пароля .

 

*

@param userID Переданное имя поль зователя .

*

@param pas sword Переданный пароль .

 

*

@ return Возвращает объект, инкапсулирующий доказательство

*

аутентификации .

 

* /

 

abstract protected Object authenticate (String userID ,

 

String password)

 

 

throws Exception;

 

/ * *

 

*

Извещает остальную часть программы о

том, что пользователь

*

аутеНТИфицирован .

 

426

Глава 8. Поведен

ч

ес ие шаблоны проектирования

 

 

к

ются суффиксом -Hook. Например, ПРИдерживаясь таких соглашений об име­

нах, метод переноса слов класса Paragraph может носить имя doHyphenation

ИЛИ hyphenationHook.

СЛЕДСТВИЕ

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

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

данию основной структуры подклассов класса AbstractTempl ate.

ПРИМЕР КОДА

Приведем код, который реализует проект, описанный в разделе «Контекст•. Сначала - код для класса AbstractLogon. В шаблоне Template Method он иг­ рает роль AbstractTemplate. Его метод шаблона называется logon. Метод logon активизирует диалоговое окно, которое предлагает пользователю ввести его Идентификатор и пароль. После того как пользователь ввел ID и пароль, метод l ogon отображает окно, которое сообщает пользователю, что идет аутен­ тификация. Это окно остается во время обращения метода l ogon к абстрактно­ му методу authenticate для аутентификации ID пользователя и пароля. Если аутентификация прошла успешно, то диалоговые окна пропадают и вызывается абстрактный метод noti fyAuthentication, чтобы известить остальные части программы о завершении аутентификации пользователя.

public abstract class AbstractLogon {

/ ** Этот метод аутентифицирует пользователя . * @pa ram frame

* Родительское окно диалогов , которые выводит на экран

*этот метод .

*@param programName Имя программы .

*/

public void 10gon (Frame frame , String programName) Object authenticationTokeni

LogonDialog 10gonDialog i 10gonDialog = new LogonDialog (frame ,

Класс LogonDialog реализует диалог, напоминающий пользователю о BBOД информации ДЛЯ входа. Переменная wa itDialog ссылается на окно, содержа­

"Log оп to "+programName) i

JDialog waitDialog = createWaitDialog (frame) i

щее сообщение ДЛЯ пользователя, аутентификация которого выполняется.

Template Method 8 427

while (true) (

waitDialog . setVisible (false) ; logonDialog . setVisible (true) ; waitDialog . setVisible (true) ; try (

String userID = logonDialog . getUserID () ; String password = logonDialog . getPassword () ; authenticationToken = authenticate (userID ,

password) ; break;

catch (Exception е) (

// Сообщает пользователю, что аутентификация

//закончилась неудачей .

JOptionPane . showМessageDialog (frame , е . getмessage () ,

"Authentication Failure" ,

JOptionPane . ERROR_МESSAGE)

}/ / try

//Аутентификация прошла успешно . waitDialog. setVisible (false) ; logonDialog. setVisible (false) ;

notifyAuthentication (authenticationToken) ;

// logon ( )

Остальная часть этого листинга просто демонстрирует абстраКТНblе методы,

определяеМblе в классе Abs tractLogon И ВblЗblваеМblе методом logon.

/ * * * Аутентифицирует пользователя, исходя из предоставленных

* I D пользователя и пароля .

*@param userID Переданное имя поль зователя .

*@param pas sword Переданный пароль .

*

@ return Возвращает Объект , инкапсулирующий доказательство

*

аутентификации.

* /

 

abstract protected Object authenticate (String userID ,

 

String password)

 

throws Exception;

/ * *

 

*

Извещает остальную часть программы о том , что пользователь

*

аутентифицирован .

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