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

GrandM-Patterns_in_Java

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

1 1 6 Глава 5. Порождающие шаблоны проектирования

URLConnect ion имеют MeToJ( getContent, который возвращает содержимое! URL, упакованное в соответствующем объекте. Если URL, например, содеРЖИТI файл gif, то метод getContent объекта URLConnection возвращает объек

Image.

Этот механизм работает следующим образом: объекты URLConnect ion игра роль инициатора запроса создания в шаблоне Factory Method. Они делегирую функции метода getContent объекту класса ContentHandler. Это абстракт­ ный класс, который играет роль Product и имеет информацию об управлени содержимым определенного типа. Объект URLConnect ion получает объеэт

класса ContentHandler через объект класса ContentHandlerFactory.

абстрактный класс, который участвует в шаблоне Factory Method в качеств интерфейса класса-фабрики. Класс URLConnect i on имеет также мето setContentHandlerFactory. Программы, в которых выполняются апплеты вызывают этот метод для предоставления объекта-фабрики, используемог всеми объектами URLConnection.

ПРИМЕР КОДА

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

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

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

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

ставляющий отчеты в журнале событий. В этом примере используются обе формышаблона Factory Method.

При чтении отчетов из журнала приложение использует объект-фабрику для создания объекта, который соответствует каждой записи в журнале. Ка­ ждый раз, когда объект-фабрика получает запрос на создание объекта, он выбирает класс для создания экземпляра, основанного на информации об отчете. Это пример объекта-фабрики, который определяет класс во время выполнения.

Система торговых терминалов - это высокотехнологичные кассовые аппараты.

Factory Method _ 1 17

Класс объекта-фабрики, который создает объекты ДЛЯ представления отче­ тов, основывается на типе журнала событий , который будет читать прило­

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

Организация классов, на которых основывается код такого примера, показана на рис. 5.5. Опишем эти классы и интерфейсы.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

«interface»

 

 

 

 

 

 

 

 

 

 

 

JournaLRecordIF

 

 

 

 

 

 

 

 

 

 

!J.

 

 

 

 

 

 

I--------------- I-I---------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

I

StartOfSaLe

I

 

 

I

 

 

SaLeLineltem

 

. . .

 

..

 

..

С

оздает

1" ..

 

 

1"

 

 

 

 

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Создает

-

 

 

-Создает

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Создает -

JournaLRecordFactoryIF nextRecord():journaLRecordIF

. . .

Создает -

 

 

 

 

 

I

 

-

 

 

- Создает

 

 

 

 

I

 

I

*

I

1

1

1

1

 

 

 

.- - - - --- - - - - - - -

---- , -- - - - - - - - - - - - - - - - - - - - - - - -

 

1

 

 

 

 

. .

 

ABCJournaLRecordFactory

 

XYZJournaLRecordFactory

....

 

 

nextRecord():JournaLRecordIF

 

nextRecord():JournaLRecordIF

 

 

 

. . .

 

. . .

 

...Создает

0. .1

1

0..1

Создает

Создает -

Создает

-

 

 

 

 

 

 

1

 

1

 

 

 

 

RecordFactoryFactory

 

 

 

«constructon)

 

 

 

 

 

RecordFactoryFactory(posType:String)

 

 

 

«misc»

 

 

 

 

 

createRecordFactory(:Datalnput):JournaLRecordFactoryIF

 

 

Рис. 5.5. Пример метода фабрики

JournalRecordIF. Объекты, которые инкапсулируют содержимое журнала собы­ тий , являются элементами класса, который реализует этот интерфейс.

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

118 Глава 5. Порождающие шаблоны проектирования

StartOfSale. Экземпляры этого класса представляют запись журнала, которая показывает начало транзакции продажи.

SaleLineItem. Экземпляры этого класса представляют запись журнала, которая содержит детали процесса продажи на кассовом аппарате.

JournalRecordFactoryIF. Этот интерфейс реализуется классами , отвечающими

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

рые реализуют интерфейс Journal Record I F. Экземпляры классов, которые

реализуют этот интерфейс, создают объекты, которые реализуют интерфейс

JournalRecordIF, например, объекты S ta rtOfSale и SaleLinel tem.

AВCJournalRecordFactory. Экземпляры этого класса отвечают за распознавание формата журнала событий для системы торговых терминалов, произведенной фирмой АВс. Экземпляры класса читают следующую запись из объекта, кото­ рый реализует j ava . i o . Datalnput, и инкапсулируют его содержимое в экзем­

плярах класса, который реализует интерфейс JournalRecordIF.

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

рый реализует j ava . i o . Datalnput, и инкапсулируют его содержимое в экзем­ плярах класса, реализующих интерфейс JournalRecordI F.

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

Можно заметить структурную схожесть меЖдУ этим примером, использующим

две формы шаблона Factory Method, и шаблоном Abstract Factory. Одна из от­

личительных характеристик шаблона Abstract Factory - клиентские объекты

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

Рассмотрим код, реализующий приложение. Сначала - листинг класса Re­

cordFactoryFactory:

puыlcc class RecordFactoryFactory

private Constructor factoryConstructor ;

Когда создается экземпляр класса, строка, показывающая тип системы терми­

налов, для которой объект будет фабрикой, передается конструктору класса.

Он получает объект j ava . l ang . reference . Constructor, который он будет

использовать для создания объектов, и делает объект Constructor значением

экземпляра переменной Facto ryConstructor.

// РОЗ Types

АВе "а.Ьс" ;

public static final String

Fadary Method 119

/* *

*Cons t ructor

*@param posType

*

Тип системы терминалов ,

для которой этот объект будет

*

создавать объект JournalRecordFactoryI F .

@ throws POSException

 

*

Если возникла проблема ,

инициализируем этот объект .

* /

public RecordFactoryFactory (Strinq posType)

 

 

 

 

 

throws POSException {

Class [ ] params

 

{ Datalnput . class } ;

Class

factoryClass ;

 

 

 

 

=

 

 

if (AВC . equals (posType»

{

factoryClass = AВCJournalRecordFactory . class ;

else (

 

 

 

 

 

 

Strinq msq

 

"Unknown POS

type : "+ роаТуре ;

throw new

java . lanq . IlleqalArqumentException (msq) ;

=

 

 

 

 

try ( factoryConstructor

=factoryClass . qetConstructor (params) ;

}catch (Exception е) (

Strinq msq = "Error while constructinq factory" ; throw new POSException (msq, е) ;

//try

//constructor ( S tring)

Метод, который создает объекты Journal RecordFactoryI F:

public JournalRecordFactoryIF createFactory (Datalnput in)

 

 

 

throws

POSException {

Object [ ]

arqs { in} ;

 

Object factory;

 

 

try (

 

 

 

 

 

factory

 

factoryConstructor . newlnstance (arqs) ;

catch

(Exception е)

(

 

=

 

 

 

Strinq msq

 

"Error creatinq factory" ;

throw new

POSException (msq, е) ;

=

 

 

//

return (JournalRecordFactoryIF) factory ; // createFactory

// class RecordFactoryFactory

120 Глава 5. Порождающие шаблоны проектирования

А теперь - интерфейс JournalRecordFactoryIF:

*

Этот интерфейс

реализуется классами, которые

*

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

*

записи журнала

для системы терминалов .

*/

public interface JournalRecordFactoryIF / * * * Возвращает объект, который инкапсулирует следующую

*запись в журнале событий .

*@th rows EOFException

*Если в журнале событий больше нет записей .

*@throws IOException

*Если при чтении следующей записи возникли

*какие-то проблемы .

*/

public JournalRecordIF nextRecord () throws EOFException, IOException ;

// interface Journa lRecordFactory I F

ДЛЯКласс AВCJournalRecordFactory реализует интерфейс JournalRecordFactoryIF

типа системы терминалов, которая называется АВс.

public class AВCJournalRecordFactory

implements JournalRecordFactoryIF

//

Типы записей .

 

private

static final String SALE_LINE_IТEМ "17" ;

private static final String START OF SALE

== "4" ;

private DataInput in;

 

private final SimpleDateFormat dateFormat

 

//

=

new SimpleDateFormat("yyyyММddННssmm") ;

Счетчик количества записей .

 

private int sequenceNumber = О ;

 

AВCJOurnalRecordFactory (DataInput input)

{

 

//

 

=

input;

 

 

in

 

 

}

 

 

constructor ( Datalnput )

 

Factory Method 121

/**

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

*в журнале событий .

*

* @ th rows EOFException

*Если в журнале событий больше нет за писей .

* @throws IOExcept ion

*Если при чтении следующей записи возникли какие -то

*проблемы .

*/

public JournalRecordIF nextRecord () throws EOFException , IOException (

String record = in . readLine () ;

StringTokenizer tokenizer;

tokenizer = new StringТokenizer (record, " , " ) ; sequenceNumber++;

try (

String recordType = tokenizer . nextToken () ;

if (recordType . equals (START_OF_SALE» ( return constructStartOfSale (tokenizer) ;

} else if (recordТype . eguals (SALE_LlNE_ITEM» return constructSaleLineltem(tokenizer) ;

else

String msg = «ипknоwn record type»; //throwif new IOException (msg) ;

catch (NoSuchElementException е )

// Это исключение рассматривается как ошибка ввода-вывода ,

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

String mзч = "record is missing зоте fields" ; IOException ioe = new IOException (msg) ;

ioe . initCause (e) ; throw ioe;

}// try

}// nextRecord ( )

private

StartOfSale constructStartOfSale (StringТokenizer tok) throws NoSuchElementException (

122 Глава 5. Порождающие шаблоны проектирования

String transactionID = tok . nextToken () ;

tOk . nextToken () ; // Пропустить индикатор способа . String timestampString = tok . nextToken () ;

Date timestamp = parseTimestamp (timestampString) :

String terminalID = tok . nextToken () ;

return new StartOfSale (terminalID , sequenceNumber, timestamp , transactionID) ;

} // cons tructStartOfSale ( S t ri ngTokeni zer)

// class ABCJourna lRecordFactory

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

С ШАБЛОНОМ FACТORY METHOD

Hashed Adapter Objects. Шаблон Hashed Adapter Objects (описанный в книге

[Grand99J) может использоваться при реализации шаблона Factory Method. Hashed Adapte!" Objects может быть полезен, если классы, которые объект-фаб­ рика инстанциирует, могут изменяться в течение работы программы.

Abstract Factory. Шаблон Factory Method применяется при создании одиночных объеГО, ктов для специфических целей без создания инициатора запроса, знающе­ как специфические классы будут инстанциироваться. Если нужно создать подходящие наборы классов объектов, то больше подходит шаблон Abstract

Factory.

Template Method. Шаблон Factory Method часто применяют совместно с шабло­ ном Template Method при определении типа Toro, что нужно создать с исполь­

зованием конфигурационной информации.

Prototype. Шаблон Prototype позволяет объекту еще одним способом взаимо­

действовать с другими объектами, не зная деталей их конструкции. длJl

Strategy. Шаблон Strategy подходит лучше, чем шаблон Template Method,

ситуаций , в которых количество вариантов поведения велико.

Abstract Factory известен также под названием Кit, или Toolkit. Этот шаблон был ранее описан в работе [GoF95].

СИНОПСИС

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

КОНТЕКСТ

Предположим, необходимо создать каркас пользовательского интерфейса, который должен работать со многими оконными системами, например, MS Windows, Моtif или MacOS, т.е. на любой платформе с сохранением свой­ ственного платформе внешнего вида и стиля (look and feel). Для каждого типа элемента окна (текстовое поле, кнопка, список и т.д.) создают абстрактный класс, а затем объявляют конкретный подкласс каждого такого класса для каж­ дой поддерживаемой платформы. В целях надежности нужно гарантировать, что все созданные объекты элементов окна предназначены для нужной плат­ формы. Здесь вступают в игру абстрактные классы-фабрики.

Абстрактный класс-фабрика определяет методы для создания экземпляра каж­ дого абстрактного класса, представляющего элемент окна пользовательского интерфейса. Конкретные классы-фабрики представляют собой конкретные подклассы абстрактного класса-фабрики, реализующего методы для создания

экземпляров конкретных классов элементов окна ДIlЯ одной и той же платформы.

С точки зрения общего контекста абстрактный класс-фабрика и его конкрет­

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

Предку положим, пишется программа, которая выполняет удаленную диагности­

компьютеров, произведенных фирмой Stellar Microsystems. Их самые старые компьютеры использовали чипы процессоров фирмы Enginola, имеющие тра­

Диционный набор комплексных команд. С тех пор фирма разработала несколь­ ко поколений компьютеров, базирующихся на собственных архитектурах RISC

с названиями еmЬег, superember и ultraember. Основные компоненты, испольна­

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

124 Глава 5. Порождающие шаблоны проектирования

Чтобы создаваемая программа знала, какие тесты запускать и как интерпретироветст ­ вать результаты, надо инстанциировать объекты, которые будут соот вовать каждому основному компонентудиагностируемого компьютера. Класс каждого объекта будет соответствовать типу тестируемогохите компонента. Это означает, что будет набор классовдля каждого варианта ар ктуры компьютера. В каждом наборе будет класс ДЛЯ компонента компьютера одного и того же типа.

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

дов. Здесь представлены только компоненты двух видов. Структура классов

компонента любого другого вида будет аналогичной. Для компонента каждого типа существует интерфейс. Каждая поддерживаемая архитектура компьютера

имеет класс, который реализует каждый интерфейс.

 

 

 

I

 

 

 

 

I

 

 

 

 

 

I

 

 

 

 

I

 

 

,

 

 

I

 

.

 

 

I

 

,

 

 

,

 

 

 

I

 

II_ _ _ _ _ _ _ _ _ _ _ _ _ _ JII

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _II

II_ _ _ _ _ _ _ _ _ _ _ _ _ _ JII

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _II

I

 

 

I

 

I

I

 

I

 

I

I

I

I

I

 

I

I

I

I

 

I

EmberCPU

EnginolaCPU

 

Engin laMMU

EmberMMU

 

Рис. 5.6. Классы диагностики

Для решения задачи нужно знать, как организовать создание объектов диагно­

стики системы. Желательно также, чтобы классы, использующие классы диаг­ ностики системы, не зависели бы от них. Для создания объектов диагностики системы можно было бы использовать шаблон Factory Method, но есть одна

проблема, которую этот шаблон не решает: необходимо, чтобы для каждой ар­

хитектуры процессора существовали свои классы диагностики системы. Если

просто использовать шаблон Factory Method, клиентские классы при запросе

на создание классов диагностики системы должны будут сообщать каждому

классу-фабрике, для какой архитектуры компьютера предназначены объектЫ

диагностики системы. Нужно найти единый способ решения следующей про­

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

ны именно ДЛЯ той архитектуры, которая нужна, но классы, использующие эти

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

моти в ы

© Система, работающая со многими продуктами, должна функционироват

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

© Должна существовать возможность задавать конфигурацию системы для ра.<.'

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

 

 

Abstract Factory 8 125

©

Обязательное условие: экземпляры классов, предназначенные для взаимо­

 

 

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

©

с этим продуктом.

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

 

©

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

Система должна быть расширяемой, чтобы иметь возможность работать

 

 

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

®

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

Интерфейса, реализуемого классом, недостаточно для того, чтобы выделить

 

 

его среди других классов, которые могут быть инстанциированы с целью

 

создания некоторого объекта.

РЕШЕНИЕ

На рис. 5.7 представлена диаграмма классов, описывающая роли, исполняемые классами в шаблоне Abstract Factory.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

«;nterface»

 

 

 

 

 

 

...Использует

 

 

 

 

 

I

 

 

 

 

 

 

FactoryIF

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

createA

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

Client

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

createB

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

...используе:

I

 

 

...

 

 

 

 

 

 

 

 

 

 

 

 

I

 

«interface»

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

WidgetAIF

 

 

r *

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ооо

 

 

 

 

 

 

 

 

,

 

 

 

t:.о

 

 

 

 

 

 

 

 

 

 

 

 

 

о

 

 

 

 

 

 

 

 

 

 

 

 

о

 

 

 

 

 

 

 

 

 

 

 

 

 

о

 

 

 

 

 

 

 

 

О

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

о

 

ОО

 

О

 

 

 

 

_ _ _ _ _ _ _ _ _ _ _ _ _ _ L _ _ О - - - - - - - - - - - - - ,ОО

 

 

 

 

L

 

 

 

 

 

Product2WidgetA

 

 

 

ProductlWidgetA

 

0 0 0

 

 

 

 

 

 

О

 

 

 

 

 

 

 

I

 

 

 

I

 

I

 

 

 

 

 

 

I

 

 

 

 

 

 

_ _ _ _ _ _ _ _ _О- - - - - - - - - - - -

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0 0 0

 

 

 

оОО

 

 

 

 

 

 

*

 

 

 

 

 

*

 

 

 

 

 

 

 

 

 

 

 

 

 

о

 

 

создает.....

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ConcreteFactory2

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

createA

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

createB

 

 

 

 

 

 

 

 

 

 

 

создает.....

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

ConcreteFactoryl

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

createA

 

 

 

 

 

 

«interface»

 

I

 

...Использует

 

 

 

 

 

 

 

 

 

 

 

createB

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

...

 

 

 

 

I

 

WidgetBIF

 

 

 

Г *

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

....Создает

 

 

 

t:о.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

О

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

---- -

 

о

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

r

 

- - - - - - L - - - - - - - - - - - - - - - ,

 

 

 

 

 

 

 

 

 

 

 

 

 

 

О

 

 

 

 

О

 

 

 

 

 

О

 

 

 

 

 

 

 

 

Создает -* ProductlWidgetB

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 5.7.

 

Клоссы в шоблоне Abstract

Factory

 

 

 

 

 

 

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