Пул об'єктів () — твірний шаблон проєктування, набір ініціалізованих і готових до використання об'єктів. Коли системі потрібно об'єкт, він не створюється, а береться з пулу. Коли об'єкт більше не потрібен, він не знищується, а повертається в пул.

Призначення

Пул об'єктів призначений для зберігання готових до використання об'єктів. Коли система потребує новий об'єкт, він запрошується з пула, нехтуючи процесом породження. А після використання повертається назад в пул замість знищення.

Умови використання

Шаблон використовується для підвищення продуктивності, якщо: об'єкти часто створюються і знищуються; система має обмежену кількість типів об'єктів, що зберігаються в Пулі. створення чи знищення об'єкта є дуже затратною операцією. Пул об'єктів може працювати як з інтерфейсами, так і з конкретними реалізаціями. Все залежить від архітектури системи, що розробляється та розв'язуваних задач.

Пул та інші шаблони

Можна зустріти сумісне використання Пула об'єктів та інших шаблонів проєктування. Наприклад, для створення об'єктів в конкретному стані можна використати Прототип. А за допомогою Одинака — створити єдиний екземпляр Пула в системі.

Поганою практикою вважається приховування Пула за іншими шаблонами проєктування. Розробник, який використовує такий підхід, не очікує вимоги повернення об'єктів, наприклад, Фабричного методу. А без повернення об'єктів сам Пул стає непотрібним. В такому випадку, правильним рішенням буде відділити реалізацію класів, що створюють об'єкти.

Особливості використання

Пул нічого не знає про реалізацію об'єктів, які зберігаються. Тому вважається, що повернений об'єкт знаходиться в невизначеному стані. Для подальшого використання його необхідно перевести в початковий стан (скидання). Наявність об'єктів в невизначеному стані перетворює Пул в «об'єктну клоаку» (object cesspool). Повторне використання може стати причиною витоку конфіденційної інформації. Тому обов'язково необхідно зчищати поля з секретними даними при скиданні, а самі дані — знищувати. Можлива ситуація, коли в Пулі не залишиться вільних об'єктів. В такому випадку, реакція на запит може бути наступною: збільшення розміру пула; відмова у видачі об'єкта; становлення в чергу і очікування звільнення об'єкта.

Реалізація

Реалізація на C#

Роздивимось варіант роботи з Пулом без обмежень в його розмірі. В такому випадку в нього можна помістити стільки об'єктів, скільки підтримує використовуємий контейнер. Якщо ж при запиті не виявиться вільного об'єкта, то буде створений новий.

В загальному випадку Пул не повинен нічого знати про спосіб створення, реалізацію і функції об'єктів, що зберігаються. Для нього важливим є тільки мати можливість дати команду скидання стану.

Створимо два інтерфейси. Перший — для скидання стану, його повинні підтримувати самі об'кти:

/// <summary> The poolable object interface </summary>

public interface IPoolable { /// <summary>Resets the object's state.</summary> void ResetState(); }

Другий — для створення об'єктів, тому що Пул не знає як саме це робити. Тут може бути як варіант з одним ключовим словом new, так і використання будь-якого шаблона проєктування.

/// <summary> The pool object creator interface. </summary> /// <typeparam name="T">Type of the objects to create.</typeparam> public interface IPoolObjectCreator<T> { /// <summary>Creates new object for a pool.</summary> /// <returns>The object.</returns> T Create(); }

Одразу реалізуємо даний інтерфейс у вигляді generic класу для створення екземплярів за допомогою конструктора без параметрів:

public class DefaultObjectCreator<T> : IPoolObjectCreator<T> where T : class, new() { T IPoolObjectCreator<T>.Create()

return new T();

Перейдемо до створення Пула. Як контейнер об'єктів використовуємо клас ConcurrentBag, реалізований в .NET4. Оскільки розмір Пула не фіксований, то його метод GetObject() завжди повертає об'єкт. Метод ReturnObject() переміщує об'єкт назад у контейнер. При цьому відбувається скидання його стану. Крім того, змінній, що тримала посилання на нього, присвоюється значення null. Властивість Count показує скільки об'єктів в даний момент знаходиться в пулі.

Повний код класу, що реалізує шаблон Пул об'єктів:

public class ObjectPool<T> where T : class, IPoolable

{ /// <summary>Object container. ConcurrentBag is tread-safe class.</summary> private readonly ConcurrentBag<T> _container = new ConcurrentBag<T>(); /// <summary>Object creator interface.</summary> private readonly IPoolObjectCreator<T> _objectCreator; /// <summary>Total instances.</summary> public int Count { get { return this._container.Count; } } /// <summary> /// Initializes a new instance of the <see cref="T:ObjectPool"/> class. /// </summary> /// <param name="creator">Interface of the object creator. It can't be null.</param> public ObjectPool(IPoolObjectCreator<T> creator)

if (creator == null) { throw new ArgumentNullException("creator can't be null");

this._objectCreator = creator;

/// <summary>Gets an object from the pool.</summary> /// <returns>An object.</returns> public T GetObject()

T obj; if (this._container.TryTake(out obj)) { return obj;

return this._objectCreator.Create();

/// <summary>Returns the specified object to the pool.</summary> /// <param name="obj">The object to return.</param> public void ReturnObject (ref T obj)

obj.ResetState(); this._container.Add(obj); obj = null;

Джерела http://andrey.moveax.ru/patterns/oop/creational/object-pool/ http://dofactory.com/Default.aspx