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

GrandM-Patterns_in_Java

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

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

lcquireReusable В пуле имеются какие-то объекты Reusable, то он удаляет

бъект Reusable из пула

и возвращает его. Если пул пустой, то

метод

lcquireReusable, если

может, создает объект Reusable. Если

метод

lcqu ireReusable не может создать новый объект Reusable, то он ожидает,

!Ока объект Reusable не будет возвращен в коллекцию.

lослезавершения работы с объектом объекты Client передают объект Resable

{етоду releaseReusable объекта ReusablePool. Метод releaseReusable воз­

Iращает объект Reusable в пул неиспользующихся объектов Reusable.

Jo многих приложениях, в которых используется шаблон Object Рооl, ограни­ Iивается общее количество создаваемых объектов Reusable. В таких случаях Iбъект ReusablePool, создающий объекты Reusable, отвечает за то, чтобы не оздавать такое количество объектов Reusable, которое бы превыщало задан­

IЫЙ максимум. Если объекты ReusablePool отвечают за ввод ограничений ко­ :ичества создаваемых ими объектов, то класс ReusablePool будет содержать lетоД, задающий максимальное количество создаваемых объектов. На рис. 5.19 rrOT метод указан под именем setMaxPoolSize.

)ЕдЛИЗАЦИЯ

lри рассмотрении задачи реализации щаблона Object Pool следует рассмотреть lекоторые вопросы.

) гр а н и ч е н и е ма к с и м а л ь н о го кол и ч е с т в а

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

<ен ограничивать количество создаваемых экземпляров некоторого класса.

па проблема рещается просто. Но для того, чтобы соблюдать это ограничение

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

Iбъектов, должен быть единственным объектом, способным создавать эти

Iбъекты.

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

ор(ы) управляемого класса закрытым и реализовать класс, управляющий пу­

ом, как статический класс-член управляемого класса. Если не контролируетсЯ труктура класса, экземплярами которого нужно управлять, можно применить

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

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

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

Object Pool 167

И с п ол ь з о в а н и е «мя г к и х» с с ыл о к (soft гefe гe n c e s)

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

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

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

«(Мягкие» ссылки реализованы в Java АР! классом j ava . lang . ref . SoftRe­ ference. Ссылка на другой объект передается конструктору объекта SoftRe­ ference. Сразу после создания объекта SoftReference его метод get воз­

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

интересное в объектах SoftReference то, что они специально предназначены

для сборщика мусора.

Если пул объектов ссылается на объекты в пуле, используя «мягкие» ссылки, то программа сборки мусора освободит память, занимаемую объектами, если на эти объекты нет других ссылок и JVM (Java Virtual Масhiпе, виртуальная маши­ на Java) почти исчерпала всю память.

О гр а н и ч е н и е р а зме р а п ул а

Существуют такие ситуации, когда «мягкие» ссылки нельзя назвать хорошим решением проблемы ограничения избыточных ресурсов, используемых объек­ тами, которыми управляет пул:

высвобождением ресурса;

если программе нужна JVM из старых версий (старше версии 1.2), нельзя

использовать «мягкие» ссылки.

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

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

Если управляемый пулом объект больше не нужен, он высвобождается, и Re­

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

Если этот объект связан с каким-либо внешним ресурсом, он должен освобо­

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

ЛИть сборщик мусора.

Способы ограничения размеров пула и использования «мягких» ссылок, как Правило, не применяются одновременно. Программа сборки мусора может

ОЧИстить объект SoftReference в любой момент времени, поэтому никто не

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

Личества объектов, содержащихся в этом пуле.

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

168

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

 

У п р а вл е н и е о бъ е к та м и состоя н и й

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

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

щаются в ожидаемое состояние. Для решения этой проблемы чаще всего при­

меняются следующие способы.

закрывали соединение с базой данных.

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

лом, используя шаблон Decorator. Например, чтобы сделать это для соеди­ нения с базой данных, следует создать объект-обертку (wrapper), который

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

СЛЕДСТВИЯ

©Использование шаблона Object Роо) позволяет избежать необходимости

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

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

нием экземпляров класса в некотором классе, отделенном от остальныХ

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

более связанный проект. При этом устраняется взаимодействие между реа­

лизацией политики создания и повторного использования и реализацией

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

ПРИМЕР КОДА

шаблона Object Роо) используют один из двух способов, которыЙ

гарантирует, что управляемые объекты не занимают слишком большой объеtt3М памяти. Такие способы либо используют «мягкие» ссылки, указывающие объекты, либо ограничивают количество объектов, которые могут находитьсЯ

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

дитсяMOryпримерт применения ого из них. Оба класса являются универсальнымИ; Они использоваться для задания пула, содержашего объекты любого вида.

Objed Роо' 1 69

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

J1СПОЛЬЗУЮЩИЙ «мягкие» ссылки.

public/ * * class SoftObjectPool implements ObjectPoolIF

*/Эта коллекция содержит управляемые объекты .

private ArrayList рооl ;

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

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

терфейса CreationIF находится в конце данного раздела.

private CreationIF creator ;

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

ляемых пулом и существующих одновременно. В переменной instanceCount

содержится число, содержащее количество объектов, существующих в данный

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

private int instanceCount; private int maxInstances ;

Поскольку этот класс представляет собой универсальный пул объектов, он не

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

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

Когда объект высвобождается и помещается в пул, пул должен убедиться, что

этот объект является экземпляром определенного класса. Класс управляемых

об

е

ктов хранится в переменной poolClass.

ъ

 

 

 

private Class poolClass ;

 

 

/ *

*

 

 

*

Const ructor

 

 

*

@pa ram poolClass

 

 

*

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

 

 

*

объектов пула .

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

*

@param creator

*

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

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

*/

public SoftObjectPool ( Class poolClass ,

) (

CreationIF creator

this ( poolClass , creator, Integer . М

AX VALUE) ;

 

_

/ / constructor (Class, CreationIF, int)

/ * *

*Constructor

*@param poolClass

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

*объектов пула .

*@param creator

*

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

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

*@param maxlns tances

*Максимальное количество экземпляров класса poolClass ,

*которым пул разрешает существовать одновременно . Если пулу

*

поступает

запрос

на создание экземпляра класса

*

poolCla s s , когда

в пуле нет объектов , ожидающих

*повторного использования , и имеется множество таких

*управляемых пулом объектов, которые используются

*

в данный момент, то

пул не будет

*

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

тех пор, пока в пул не будет

*возвращен объект для повторного исполь зования .

* /

public SoftObjectPool ( Class poolClass , CreationIF creator, int maxInstances )

this . creator = creator; this .poolClass = poolClass ; pool = new ArrayList() ;

/ / constructor (Class , C reation I F, int, int)

/ * *

 

 

*

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

*

исполь зования .

Реальное количество может быть меньше

*

этого значения ,

поскольку возвращаемая

 

величина - это количество " мягких" CCbU10K

Object Рооl 171

*

в пуле . Некоторые

*

или все такие " мягкие" ссылки могут быть очищены сборщиком

*

мусора .

 

* /

 

public int getSize ( ) (

 

 

synchronized (pool)

 

 

return pool . size ( ) ;

 

 

} // s ynchronized

 

 

/ / getSi ze ( )

 

/ * *

 

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

* существующих в дaHHЬ момент .

 

*/

 

public int getInstanceCount ( )

 

 

return instanceCount;

 

}

// get lnstanceCount ( )

 

/* * * Возвращает максимальное количество управляемых пулом * объектов , которым пул разрешает существовать одновременно .

*/

public int getм8xInstances ( ) return maxInstances ;

// getMax lnstances ( )

/ * * * Задает максимальное количество управляемых пулом объектов ,

* которым этот пул разрешает существоват ь одновременно .

*

*

Если к пулу поступает запрос на создание экземпляра класса

*

poolClas s , когда в пуле нет объектов, ожидающих

*повторного использования, и имеется множество таких

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

*

момент, то пул

не будет создавать объект до тех пор, пока

в пул не будет

возвращен объект для повторного

*

использования .

 

*

 

 

*@param newValue

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

* пулом объектов, которые могут существовать одновременно .

172 Глава 5.

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

 

*

 

 

Установка в этой переменной значения,

 

*

 

 

которое меньше

значения , возвращаемого методом

 

*

 

 

get lns tanceCount , не повлечет за собой удаление объектов

*

 

 

из пула . Просто предотвращается

 

*/

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

 

*

 

 

 

public void setмaxInstances (int newValue)

 

 

maxInstances = newValue;

 

 

/**

/

setMax lnstances ( )

 

 

 

 

 

 

 

 

 

 

 

 

*

 

Возвращает из пула объект . При пустом пуле будет создан

 

*

 

объект,

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

 

*

 

больше

или равно значению, возвращаемому методом

 

*

 

getMaxlnstances . Если количество управляемых пулом

 

*

 

объектов преВЬПllает это значение ,

то данный метод

 

*

 

возвращает nul l .

 

 

 

 

* /

 

 

 

 

 

 

 

 

 

public Object getObject ( )

 

 

 

 

synchronized (pool)

{

 

 

 

 

 

 

Object thisObject = removeObject ( ) ;

 

 

 

 

if

(thisObject!=null)

 

I

 

 

 

 

return thisObject;

 

 

 

 

 

 

/ /

i f

thi sObj ect

 

 

 

 

 

if (getInstanceCount () < getмaxInstances () ) {

 

 

 

 

 

return createObject ( ) ;

 

 

 

 

 

else

{

 

 

 

!

 

 

 

}

/ /

i f

 

 

 

 

 

 

/ /

return null ;

 

 

 

j

/ *

*

synchroni zed (pool )

 

 

}

// getObj ect ( )

 

 

 

 

*

 

Возвращает из пула объект . При пустом пуле будет

 

*

 

создан

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

 

*

не

больше или равно значению, возвращаемому методом

 

*

getMaxlns tances . Если количество управляемых пулом объектов

превыщает

это значение ,

то данный метод будет ждать до тех

 

*

пор,

пока

какойнИбудь

объект не

станет доступным для

 

*

повторного использования .

 

 

*

 

 

*

@ throws

InterruptedException

 

 

Object Pool 173

*Если вызывающий поток был прерван .

*/

public Object waitForObject( ) throws InterruptedException synchronized (pool) {

Object thisObject = removeObject ( ) ; if (thisObject ! =null)

return thisObject;

}// if thisObj ect

if (getInstanceCount ( ) < getмaxInstances ( » { return createObject ( ) ;

else { do

 

/ /

Ожидать извещения

о том ,

что объект был возвращен

 

//

в пул .

 

 

 

рооl . wait ( )

 

 

 

thisObject = removeObject ( ) ;

 

 

}

while

(thisObject==null) ;

 

 

return

thisObject;

 

 

}

/ / i f

 

 

 

 

/ /

synchroni zed (poo l )

 

 

// wa i t Fo rObj ect ( )

/* *

* Удаляет объект из коллекции пула и возвращает его . * /

private Object removeObject ( ) while (pool . size ( » O) {

SoftReference thisRef

= (softReference)pool . remove (pool . size () -l) ; Object thisObject = thisRef . get ( ) ;

if (thisObject!=null) return thisObject;

} / / i f thi sObject instanceCount- ;

/ / wh ile

return null ;

/ / removeObject ( )

/ * * * Создает объект , управляемый этим пулом .

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

* /

private Object createObject () {

 

Object newObject = creator . create () ;

 

instanceCount++;

 

return newObject;

}

// createObj ect ( )

/ * *

*

Освобождает объект, помещая его в пул для повторного

*

использования .

*

 

*

@param obj

*

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

*

/

public void release ( Object obj ) {

/ / по nul ls

if ( obj == null ) {

throw new NullPointerException () ;

}/ / i f null

if ( ! poolClass . isInstance (obj) ) {

String actualClassName = obj . getClass ( ) . getName ( ) ; throw new ArrayStoreException (actualClassName) ;

} / / if i s l nstance synchronized (pool) pool . add (obj) ;

//

Известить ожидающий поток о том, что объект помещен

/ /

в пул .

роо! . notify ( ) ; / / s ynchronized

/ / release ( )

/ / cla s s SoftObj ectPool

Теперь рассмотрим листинг класса, применяющего друryю технологию, oгpa

 

ДЛЯ

э

ничивающую количество объектов в пуле. Те фрагменты кода, которые совпа

дают с фрагментами кода

 

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

public class ObjectPool implements ObjectPoolIF { private int size ;

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

Object Pool 175

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

иая экземпляра с именем size.

/**

*

Этот массив содержит объехты,

хоторые ожидают многохратного

*

использования .

им

управляют ,

хах стехом .

*/

 

 

 

private Object[]

роо!

 

 

/**

 

 

 

*

Внутренние операции синхронизируются с использованием этого

*

объехта .

= new Object () ;

"/

private Object lockObject

Более подробное объяснение объектов блокировки содержится в описании шаблона Intemal Lock Object.

/" *

" Cons tructor

*

*param poolClass

*Класс объехтов пула . " param creator

* Объехт , хоторому пул будет делегировать ответственность

*за создание управляемых им объехтов . " param capacity

*Количество неиспользуемых объехтов, содержашихся

" в данный момент в пуле .

*param maxlnstances

*

Махсимальное холичество эхэемпляров хласса poolClas s ,

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

*/

 

public ObjectPool ( Class poolClass,

 

CreationIF creator,

size =

int capacity,

int maxInstances ) (

О ;

this . creator = creator;

this .maxInstances = maxInstances ;

роо! =

(Object[ ] )Array . newInstance (poolClass , capacity) ;

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