// След инстанциране, с пула се работи чрез:
// метода Draw() за извличане на обект от пула, например:
// object obj = pool.Draw();
// метода Return() за връщане на обект в пула, например:
// pool.Return(obj);
// свойството IsLimited, което връща дали пулът е ограничен
// Наследяваме ResourceWrapperBase за да извикаме Destroy()
// за всички обекти в пула, когато той се унищожава
public class ObjectPool : ResourceWrapperBase
{
private const int DEFAULT_MIN_OBJECTS = 4;
private const int UNLIMITED = -1;
// обект-стратегия за създаване и унищожаване на обекти
private IObjectPoolStrategy mStrategy;
private Stack mItems; // хранилище за обектите в пула
private int mInitialObjects; // първоначален брой обекти
private int mMaxObjects; // максимален брой обекти
// Създава обекти чрез прототип. Пулът е неограничен, а
// първоначалният брой е по подразбиране
public ObjectPool(IObjectPrototype aPrototype) :
this(aPrototype, DEFAULT_MIN_OBJECTS)
{
}
// Създава aInitialObjects обекта предварително
// чрез прототип. Пулът е неограничен
public ObjectPool(IObjectPrototype aPrototype,
int aInitialObjects) :
this(aPrototype, aInitialObjects, UNLIMITED)
{
}
// Създава aInitialObjects обекта чрез прототип.
// Пулът е ограничен до aMaxObjects
public ObjectPool(IObjectPrototype aPrototype,
int aInitialObjects, int aMaxObjects)
{
if (aPrototype == null)
{
throw new ArgumentNullException("prototype");
}
// Действителната инициализация се случва в Init()
Init(aInitialObjects, aMaxObjects, aPrototype, null);
}
// Създава обекти чрез стратегия. Пулът е неограничен.
// Първоначалният брой е по подразбиране
public ObjectPool(IObjectPoolStrategy aStrategy) :
this(aStrategy, DEFAULT_MIN_OBJECTS)
{
}
// Създава aInitialObjects обекта чрез стратегия.
// Пулът е неограничен
public ObjectPool(IObjectPoolStrategy aStrategy,
int aInitialObjects) :
this(aStrategy, aInitialObjects, UNLIMITED)
{
}
// Създава aInitialObjects обекти чрез стратегия.
// Пулът е ограничен до aMaxObjects
public ObjectPool(IObjectPoolStrategy aStrategy,
int aInitialObjects, int aMaxObjects)
{
if (aStrategy == null)
{
throw new ArgumentNullException("strategy");
}
Init(aInitialObjects, aMaxObjects, null, aStrategy);
}
// Метод за инициализация. Извиква се от конструкторите
private void Init(int aInitialObjects,
int aMaxObjects, IObjectPrototype aPrototype,
IObjectPoolStrategy aStrategy)
{
// Ако aMaxObjects == UNLIMITED, пулът е неограничен
if (aInitialObjects < 0 ||
(aMaxObjects != UNLIMITED &&
aMaxObjects < aInitialObjects))
{
throw new ArgumentException(
"initialObjects < 0 or maxObjects < initialObjects");
}
mInitialObjects = aInitialObjects;
mMaxObjects = aMaxObjects;
mStrategy = aStrategy;
if (mStrategy == null)
{
mStrategy = new DefaultObjectPoolStrategy(aPrototype);
}
// Създаваме минимума обекти
mItems = new Stack(mMaxObjects);
for (int i = 0; i < mInitialObjects; ++i)
{
mItems.Push(CreateObject());
}
}
// Връща дали пулът е ограничен
public bool IsLimited
{
get
{
return mMaxObjects != UNLIMITED;
}
}
// Извлича свободна инстанция от пула. Ако пулът е
// празен, се разширява, а ако не може да се разшири,
// се получава изключение
public object Draw()
{
lock (mItems)
{
// Тук сме сигурни, че се изпълнява само една нишка
if (mItems.Count > 0)
{
return mItems.Pop();
}
// Тук сме попаднали, ако първоначално или
// след заключването е нямало свободни елементи.
// Проверяваме може ли да разширим пула
int itemsToAdd;
if (mMaxObjects == UNLIMITED)
{
itemsToAdd = 1;
}
else
{
itemsToAdd = mMaxObjects - mInitialObjects;
if (itemsToAdd == 0)
{
throw new InvalidOperationException(
"The pull is empty and can not grow further.");
}
}
for (int i = 0; i < itemsToAdd; ++i)
{
mItems.Push(CreateObject());
}
// Гарантирано е, че имаме поне един елемент в пула
return mItems.Pop();
}
}
// Връща дадена инстанция обратно в пула
public void Return(object aInstance)
{
if (aInstance == null)
{
throw new ArgumentNullException("instance");
}
lock (mItems)
{
mItems.Push(aInstance);
}
}
// Наследниците на пула могат да предефинират
// създаването и унищожаването на обекти
protected virtual object CreateObject()
{
return mStrategy.Create();
}
protected virtual void DestroyObject(object aInstance)
{
mStrategy.Destroy(aInstance);
}
// Метод от ResourceWrapperBase - унищожава обектите в пула
protected override void DisposeManagedResources()
{
foreach (object instance in mItems)
{
DestroyObject(instance);
}
base.DisposeManagedResources();
}
}
|