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

GrandM-Patterns_in_Java

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

 

 

 

 

Inteгface and Abstгact Class - 85

/ * *

 

 

 

 

*

Возвращает узел ,

следующий з а данным узлом в связном

*

списке, или nul l ,

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

* /

 

 

 

 

public DoubleLinkIF getNext ()

( return next;

/ * *

 

 

 

 

*

Задает узел ,

которьм должен

следовать з а данньш узлом

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

 

 

 

*

 

 

 

 

 

*

@param node

 

 

 

 

*

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

*

в связном списке , или nul l , если этот уэел -

*

последний в списке .

 

 

*/

 

 

 

 

public void setNext (DoubleLinkIF newValue)

{

 

next = newValue ;

 

 

 

}

// setNext ( DoubleLinkIF)

 

 

/ * *

 

 

 

 

*

Возвращает узел,

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

*

или nul l , если это первьм узел .

 

*/

 

 

 

 

public DoubleLinkIF getPrev ()

{ return previous ;

/ * *

 

 

 

 

*

Задает узел ,

которьм должен

предшествовать данному узлу .

*

 

 

 

 

 

*

@param node

 

 

 

 

*

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

данному узлу

*

в связном

списке , или nul l , если этот узел -

*

первый в

списке .

 

 

*/

 

 

 

 

public void setPrev (DoubleLinkIF newValue)

{

 

previous = newValue ;

 

 

 

// setPrev ( DoubleLinkIF)

 

 

} // class Abst ractDoubleLink

 

 

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

С ШАБЛОНОМ INTERFACE AND ABSTRACT CLASS

Interface. Шаблон Interface and Abstract Class использует шаблон Interface.

Abstract Superclass. Шаблон Interface and Abstract Class использует шаблон Abstract Superclass.

Шаблон ImmutabIe является основным не потому, что его используют многие raxDстальные шаблоны, а потому, что чем чаще его применяют в подходящих мес­

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

СИНОПСИС

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

КОНТЕКСТ

Объекты значений (value objects) - это объекты, основное назначение которых скорее заключается в том, чтобы инкапсулировать значения, а не в том, чтобы

определять поведение. Например, в классе j ava . awt . Rectang le инкапсули­ рованы данные о расположении и размерах прямоугольника.

Если множество объектов имеет общий доступ к одному и тому же объекту

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

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

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

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

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

ные затраты на синхронизацию доступа к состоянию общего объекта.

Шаблон ImmutabIe позволяет избежать таких проблем. Он объявляет класс та­

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

не меняется после их создания.

допустим, проектируется игра с участием многих игроков. Программа включа­

ет размещение и случайное перемещение объектов по игровомуДIlЯполю. При

проектировании классов для этой программы определяется, что представ­

ления позиции объектов на игровом поле нужно использовать неизменные

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

поле,

представлена на рис. 4. 1 4.

х

 

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

Класс

Posi tion имеет

енные

и

 

перем

 

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

Роs itiоп.
Рис. 4.14. Неизменная позиция
Position
«constructor» Position(x:int:. y:int) «misc»
getx( ):int getY( ):int
Offset(x:int:. y:int):Position

ImmutabIe 87

х и у. Класс также содержит методы ДЛЯ считывания значений х и У, связанных с его экземплярами. И наконец, он имеет метод, который создает новый объект

Роs iti оп. Параметры метода offset задают смещение х и у по отношению к существующему расположению на игровомх поле. Класс не имеет каких-либо методов, изменяющих его переменные и у. В случае изменения позиции объ­ екта нужно будет создать новый объект

моти в ы

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

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

©Если несколько потоков одновременно пытаются изменить содержимое

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

©Альтернативой изменению содержимого объекта значений является замена

всего объекта другим объектом, имеющим другое содержимое.

®Если содержимое объекта изменяется многочисленными потоками, то за­

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

®Замена объекта значений обновленным предусматривает копирование не­

изменяемых значений из прежнего объекта в новый. Если изменения объ­

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

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

РЕШЕНИЕ

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

менными, запрещая любые изменения их состояния после их создания. Это

реализуется следующим образом: в классах этих объектов не объявляются ни­ какие методы (за исключением конструкторов), которые изменяют информа­

цию о состоянии. Структура такого класса представлена на рис. 4. 15.

ImmutableCLass

«constructor» ImmutableCLass «misc»

getAttri butel getAttribute2 getAttribute3

Рис. 4.15. Пример неизменяемого класса

Заметим, что класс имеет методы доступа для считывания информации о со­ стоянии, но не дЛя ее записи.

РЕАЛИЗАЦИЯ

Существуют два момента, о которых нужно знать при реализации шаблона

ImmutabIe:

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

переменных экземпляра класса;

любой метод, который получает информацию о новом состоянии объекта,

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

Одно небольшое замечание, связанное с реализацией шаблона ImmutabIe:

обычно в1этом. шаблоне не содержится объявлений переменных с модификато­

ром f iпа Значения результирующих переменных экземпляра обычно задают­ ся в рамках своего класса. Однако значения переменных экземпляра неизмен­

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

СЛЕДСТВИЯ

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

©Неизменный объект частощиспользуется.nf\vnnимпстьв качестве значения атрибута другого

-- о . - _ · · .. по синхронизации доступа к такому

ImmutabIe 89

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

®Операции, которые должны были бы изменять состояние объекта, создают

новый объект. Для изменяемых объектов такие затраты не характерны.

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

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

иtoLowerCase и substring, вычисляют новую последовательность символов

возвращают ее в новом объекте String.

ПРИМЕР КОДА

Ниже приводится примерный код для класса Pos ition, описанного в разделе «Контекст» :

class Position Х; private int У; private int

public Position (int х ,

int у) (

this . x

=

Х;

 

 

 

this . y

=

У;

 

 

 

// cons tructor ( i nt,

i n t )

Х;

public int getx ()

return

public int gety ()

return

У;

 

 

 

public Position offset (int xOffset , Int yOffset)

 

return new Position (x+xOffset, y+yOffset) ;

}

// offset ( in t , int)

//

class Pos ition

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

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

С ШАБЛОНОМ IMMUTABLE

Single Тhreaded Execution. Шаблон Single Threaded Execution чаще всего исполь­

зуется ДЛЯ координирования многопоточного доступа к совместно используе­

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

необходимости использования шаблона Single Threaded Execution или коорди­ нации доступа любого другого вида.

Read-Only Interface. Шаблон Read-Only Interface является альтернативой шаб­ лону ImmutabIe. Он позволяет некоторым объектам изменять объект значений,

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

Шаблон Marker Interface редко применяется без служебных классов. Однако он

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

ментальном характере объявления классов.

СИНОПСИС

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

КОНТЕКСТ

Класс Obj ect в языке Java задает метод equals. Аргумент метода equals мо­

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

в классе Obj ect равнозначна оператору == . Он возвращает true, если переда­

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

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

и тех же значений, они соответствующим образом должны заместить метод equals.

Контейнерные объекты, например, j ava . util . ArrayList, вызывают метод equals объекта во время поиска в пределах их содержимого с целью нахожде­

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

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

ЛЯются ли одинаковыми два объекта, вместо обращения к реализованному в классе Obj ect методу equals лучше воспользоваться оператором = = . Если

контейнерный класс способен определить, что объект поиска принадлежит

классу, в котором не замещается метод equals, то этот контейнерный класс может использовать оператор == вместо вызова метода equals. При таком

ПОдходе проблема состоит в том, что нет способа, который определял бы нали­ чие замещения метода equals в произвольном классе объекта.

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

СОобщить им об уместности использования оператора == при проверке равенства объектов класса. Можно задать интерфейс с названием Equ a l Byldent i ty,

Marker Inteгface 93

реализует этот интерфейс, и служебный класс Ut i l i ty, осведомленный об ин­

терфейсе MarkerIF. Диаграмма взаимодействия между этими классами пред­

ставлена на рис. 4. 17.

1: operation1(:Unmarked)

1: operationl(:Marked)

Рис. 4.17. Взаимодействие в шаблоне Marker Inteгface

Экземпляры класса Uti l i tyClass имеют метод operation l . Передаваемый этому методу параметр может представлять собой объект, который реализует

ИЛИ не реализует интерфейс MarkerIF.

РЕАЛИЗАЦИЯ

Суть шаблона Marker Interface состоит в том, что объект, реализующий либо не реализующий маркер-интерфейс, передается методу служебного класса. Соот­ ветствующий такому объекту формальный параметр обычно объявляется как имеющий тип Obj ect. Иногда уместно объявить такой параметр как относя­ щийся к более конкретному классу.

Существует также возможность в шаблоне Marker Interface использовать ин­

терфейс, в котором объявлены методы. Такой интерфейс, используемый в ка­ честве маркера-интерфейса, обычно является наследником «чистого» марке­ ра-интерфейса.

Если объявление класса предполагает реализацию маркера-интерфейса, то это

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

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

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

щению этого. Например, объявить класс как final и тем самым воспрепятст­ Вовать созданию подклассов или объявить как final его метод equals и тем самым запретить его замещение.

СЛЕДСТВИЯ © Экземпляры служебных

классов могут делать выводы, касающиеся объектов,

передаваемых их методам,

вне зависимости от того, экземплярами какого

определенного класса эти объекты являются.

Отношения между служебным классом и маркером-интерфейсом ЯВЛЯЮТСЯ

прозрачными ДЛЯ всех остальных классов, за исключением классов, реали­ зующих интерфейс.

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

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

Реализуя интерфейс Serial i z able, класс указывает на то, что его экземпляры могут быть сериализированы. Экземпляры класса Obj ectOutputStream за­ писывают объекты в виде байтовых потоков, которые экземпляр класса Obj ect InputStream может читать и превращать обратно в объект. Преобразо­ вание объекта в поток байтов называется серuалuзацuеЙ. Существуют причины, почему экземпляры некоторых классов не должны подвергаться сериализации. Поэтому класс Obj ectOutputStream не выполняет сериализацию тех объек­ тов, класс которых не реализует интерфейс Seriali zable, указывающий на разрешение сериализации.

ПРИМЕР КОДА

в качестве примера использования шаблона Marker Interface рассмотрим класс реализующий структуру данныхи в виде связного списка. В конце листинга нахо дятся методы find, findEq findEquals. Их назначение состоит в том, чтоб обнаружить узел LinkedList, ссылающийся на заданный объект. Только оди

из трех методов - find - является открытым. Метод findEq выполняет необ ходимые проверки равенства при помощи оператора == , а метод findEquals при помощи метода equals объекта, ради которого проводится поиск. Мето find решает, какой из двух методов (findEq или findEquals) долженпро быт вызван. Для этого он определяет, реализует ли объект, ради которого водит ся поиск, маркер-интерфейс EqualByIdentity.

public class LinkedList implements Cloneable , java . io . Serializable

/ * *

 

 

*

Найти в связном списке объект , равный данному объекту .

Обычно равенство

определяется путем вызова метода equals

*

данного объекта .

Но если данньм объект реализует интерфейс

*/

EqualByldentity,

то равенство

будет определяться с помощью оператора

 

(

public LinkedList find (Object target) {

 

if

(target == null I I target instanceof EqualByIdentity)

 

 

return

findEq(target) ;

 

 

else

 

 

 

/ /

return

findEquals (target) ;

 

/ *

find ( Object)

 

*

 

 

 

*

Найти в связном списке объект,

равный данному объекту .

*

Равенство

определяется с помощью оператора

i

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