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

GrandM-Patterns_in_Java

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

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

СИНОПСИС

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

КОНТЕКСТ

Нужно написать классы Д Л Я предоставления последовательного доступа (толь­ ко для чтения) к некоторым структурам данных. Допустим, эти классы будут

реализовывать интерфейс j ava . util . Iterator.

Интерфейс Iterator содержит метод, который называется remove. В доку­ ментации сказане, что назначение метода remove - удалять объекты из источ­ ника после их извлечения. В описании метода remove сказано также, что этот метод необязательныЙ. Реализация данного метода может просто генерировать исключение UnsupportedOperationException.

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

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

торый генерирует исключение UnsupportedOperationException при вызове

этого метода (рис. 4.9).

МОТИВЫ

©Нужно гарантировать, чтобы общая логика для связанных классов реализо­

вывалась одинаково для каждого класса.

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

кой излишнего кода.

©

®

Нужно упростить написание связанныхво классов.

Нужно задать общее поведение, хотя многих ситуациях наследование не са­ мый подходящий способ его реализации (см. шаблон Delegation).

'6 8 Глава 4. Основные шаблоны проектирования

 

 

«interface»

 

 

 

Iterator

 

 

 

 

 

 

 

hasNextO : boolean

 

 

 

next() : Object

 

 

 

remove() : void

 

 

 

 

 

 

 

*"

 

 

 

II

 

 

 

I

 

 

 

I

 

 

 

I

 

 

 

I

 

 

 

AbstractItera tor

 

 

 

 

 

 

 

remove()

 

 

 

 

 

 

 

1

 

ArrayIterator

NullIterator

 

 

 

 

 

Рис. 4.9. Итераторы и их абстрактный суперк.ласс

РЕШЕНИЕ

Реализуем общую логику связанных классов в суперклассе. Варианты поведения, зависящие от конкретного наследника, поместим в методы с одинаковой сиг­ натурой. Сделаем эти методы абстрактными в нашем суперклассе. На рис. 4. 1О представлена подобная структура.

Опишем роли, которые играют классы в рамках шаблона Abstract Superclass.

Abstract Superclass. Класс, выступающий в этой роли, представляет собой абст­

рактный суперкласс, в котором инкапсулирована общая логика связанных клас­

сов. Связанные классы расширяют этот класс. Таким образом, они могут на­

следовать его методы. Методы с одинаковыми сигнатурами и общей логикой

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

с зависящей от конкретного подкласса данного суперкласса логикой, но с оди­

наковыми сигнатурами, объявляются в абстрактном классе как абстрактные

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

методы с такими же сиmатурамии т.д..

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

конкретными классами. Методы, общие Д Л Я этих связанных классов, помеща­ ются в абстрактный суперкласс.

Общая логика, которая не представлена в общих методах, помещается в общие

util.
« KOHT KCT» .

Abstract Superclass 77

AbstroctSupercloss

соттопОрl соттопОр. 2

. .

voriontOpl vorionWpZ... ..

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

I

(oncreteCLassl

 

 

(oncrete([ass2

 

 

..

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

...

 

 

...

 

 

 

 

variantOpl

 

 

variantOpl

 

 

 

variantOp2

 

 

variantOp2

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 4.10.

Шаблон Abstract Superclass

 

 

РЕАЛИЗАЦИЯ то

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

СЛЕДСТВИЯ

© Тестирование будет занимать меньше времени, так как уменьшается коли­ чество кода.

® Использование шаблона Abstract Superclass приводит к появлению зависи­ мости между суперклассом и его подклассамидля . Изменение суперкласса мо­ жет иметь нежелательные последствия некоторых подклассов.

ПРИМЕНЕНИЕ В JAVA- API

Класс j ava . awt . AWTEvent это абстрактный класс Д Л Я классов, инкапсули­

рующих события, связанные с GUI (Graphical User Iпtеrfасе, графический ин­

терфейс пользователя). Он определяет несколько методов, которые являются общими ДЛЯ классов событий.

ПРИМЕР КОДА

в качестве примера рассмотрим реализацию классов из раздела Реализация этих классов взята из ПОorgфирмы. clickblocksClickBlocks,. которое вы можете найти на сайте этой книги в пакете

78 Глава 4. Основные шаблоны проектирования

Листинг класса AbstractIterator: /**

*Этот абстрактный класс очень удобен ,

*поскольку позволяет определять итераторы

*путем реализации только одного метода getNextElement ( ) .

*/ abstract public class AbstractIterator implements Iterator (

private Object nextElementi

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

*/

protected void init () { nextElement = getNextElement () i

} // init ( )

/**

*Этот метод возвращает следующий элемент

*в просматриваемой структуре данных .

*Если следующего элемента нет , то возвращает сам себя .

*/

public abstract Object getNextElement () i

/** *

* /

Возвращает true , если в структуре данной итерации есть еще не пройденные элементы .

public boolean hasNext () { return nextElement!=this i

} // hasNext ( )

/**

* Возвращает следующий элемент в итерации .

*

@except ion NoSuchElementException Итерация не имеет больше

*

элементов .

*/

public Object next ( ) {

if" (nextElement=this)

Abstract Superclass - 79

throw new NoSuchElementException () i // i f =

Object previous= nextElementi nextElement getNextElement () i return previous i

// next ( )

/** * Удаляет из базовой коллекции последний элемент, возвращенный

*методом next .

*@except ion UnsupportedOpe rationException

*Если операция удаления не поддерживается этим

*итератором .

*/

public void remove () {

throw new UnsupportedOperationException () i

}// remove ( )

// class Abstractlterator

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

С ШАБЛОНОМ ABSTRACT SUPERCLASS

лInterfaceн and AЬstract Class. Шаблон Inteгface and Abstract Class использует шаб­

о Abstract Superclass.

Template Method. Шаблон Template Method использует шаблон Abstract

Superclass.

:ИНОПСИС

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

I(OHTEKCT

ГIредположим, при проектировании приложения нужно сокрыть класс или <лассы, которые реализуют некоторое поведение, и поэтому их делают закры­ гыми и реализующими некий открытый интерфейс. Кроме того, чтобы такая Jеализация была логичной и удобной, классы должны наследоваться от общего lбстрактного класса. Но неизвестно, что сделать предком этих классов - ин­ герфейс или абстрактный класс.

МОТИВЫ

©При помощи шаблона Interface интерфейсы в языке Java могут использо­ ваться для сокрытия конкретного класса, реализующего поведение, от кли­

ентов этого класса.

©Инкапсуляция общей логики с помощью шаблона Abstract Superclass в су­

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

зации. Можно также снизить объем работ по имплементации с точки зре­ ния повторного использования кода.

®Если специалисты имеют возможность использовать два разных способа

улучшения организации классов, то, как правило, тенденция такова, что

нужно выбирать либо тот, либо другой.

РЕШЕНИЕ

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

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

Interface and Abstract Class 81

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

При возникновении двух этих требований в рамках одной задачи используют и интерфейс, и абстрактный класс (рис. 4. 1 1).

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

1

 

 

I

 

 

 

 

 

 

 

 

 

 

 

ИСПОЛl.зует

 

j

 

 

 

 

 

 

 

Client

 

 

 

«interface»

I

 

1 1

 

 

 

1

"\

+ServiceIF

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

*

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

I

,

 

I

 

 

 

 

 

 

 

 

 

 

r1

 

 

 

 

 

 

 

 

 

 

Abstract5ervice

 

 

 

 

 

 

 

ConcreteService1I

 

 

 

 

 

. .I .

 

 

 

 

 

 

 

 

 

 

 

 

 

I

 

I

I

 

 

J

 

 

 

 

ConcreteService2

Рис. 4.11. Интерфейс и абстрактный класс

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

возможность, - закрытым.

СЛЕДСТВИЕ

©Использование шаблона Interface and Abstract Class позволяет получить все преимущества интерфейсов и абстрактных классов.

ПРИМЕНЕНИЕ В JAVA API

Пакет j avax . swing . table содержит интерфейсы и классы для работы с таб­

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

объект должен быть экземпляром некоторого класса, реализующего интерфейс

82 Глава 4. Основные шаблоны проектирования

j avax . swing . table . TableModel. Кроме того, в этом пакете содержится класс AbstractTableModel. AbstractTableModel - это абстрактный класс,

который содержит некоторую логику, задаваемую по умолчанию и полезную при реализации методов, объявленных в интерфейсе TableModel. И наконец, существует конкретный класс DefaultTableModel, который инстанциируется по умолчанию при создании таблицы. Эти отношения показаны на рис. 4. 12.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

javax.swing.table

I

 

 

 

 

 

 

 

 

 

Использует

 

 

 

 

«interface»

 

 

I

JТaЫe

 

 

 

 

 

 

I

 

 

 

I 1

 

1'1

 

1)I.

 

 

 

I

 

 

 

J

+TableModeL

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

 

 

 

I

 

 

 

 

 

 

 

 

I

 

 

I

 

I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

+AbstroctTobleModel

 

I +DefauLtТableModeL I

Рис. 4.12. Отношения внутри интерфейса javax.swing.tabIe

ПРИМЕР КОДА

Пример кода ДЛЯ шаблона Interface and Abstract Class состоит из интерфейса

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

зывается двусвязный список (doubIy linked list). Класс DoubleLinkedListMgr

выполняет различные операции вставки и удаления элементов двусвязного

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

связного списка были экземплярами какого-либо определенного класса. Он

только требует, чтобы все элементы реализовывали интерфейс DoubleLinkIF.

Существует абстрактный класс AbstractDoubleLink, который реализует ин­

терфейс DoubleLinkIF. Расширение класса AbstractDoubleLink - это удоб­

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

в двусвязном списке.

Эти классы и интерфейс входят в пакет org . clickblocks . dataStructure

ПО ClickBlocks, находящеroся на сайте этой книги.

Interface and Abstract Class _ 83

Двусвязиый список

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

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

Вставка или удаление элемента из двусвязного списка всегда требует од­ ного и того же количества времени независимо от того, сколько в нем элементов. Недостаток состоит в том, что при поиске n-го элемента в дву­ связном списке нужно просмотреть первые n элементов. Чем больше n, тем больше требуется времени. На поиск n-го элемента в массиве затра­ чивается всегда одно и то же количество времени, независимо от размера массива.

I

 

first:Objeg

предшествующий элемент .....

 

 

 

 

 

 

 

I

 

:Object

 

 

 

 

 

 

 

предшествующий элемент .....

 

 

 

 

 

 

 

 

I

 

 

:Object ,

 

 

 

 

 

 

 

предшествующий элемент .....

 

 

 

 

 

 

 

 

I

 

 

LiI t;Obi !:t

 

 

 

 

 

 

I

следующий элемент .....

I

следующий элемент .....

I

следующий элемент .....

I

Рис. 4.13. Двусвяэный список

84 Глава 4. Основные шаблоны проектирования

Ниже представлен листинг интерфейса DoubleLinkIF:

public/ * * interface DoubleLinkIF (

*

* Возвращает узел , следующий за данным узлом в связном */списке , или nul l , если данный узел - последний .

public DoubleLinkIF getNext ()

 

/**

 

 

*

 

Задает узел , KOTOPbrn должен

следовать з а дaHHЬ узлом

*

 

в связном списке .

 

*

 

@param node

 

*

 

Узел, КОТОРЫЙ должен следовать з а данным узлом

*

/

в связном списке , или nul l ,

*

если зтот узел - последний в списке .

*

 

public void setNext(DoubleLinkIF newValue)

/**

 

 

*

/

Возвращает узел, KOTOPbrn должен предществовать данному

*

в связном списке , или nul l ,

если это первый узел .

*

 

public DoubleLinkIF getPrev ()

 

/ * *

 

 

*

 

Задает узел , KOTOPbrn должен предществовать данному узлу

*

 

 

 

* в связном списке .

 

*

 

@param node

 

*

 

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

*

 

в связном списке , или nul l ,

* /

если этот узел - первый в списке .

*

 

public void : setPrev (DoubleLinkIF newValue)

} //

interface DoubleLinkIF

 

А теперь - листинг абстрактного класса AbstractDoubleLink, который лизует интерфейс DoubleLinkIF.

public aЬstract class AbstractDoubleLink implements DoubleLinkIF (

private DoubleLinkIF previous ; private DoubleLinkIF next;

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