Object Pool Design Pattern


What is object pool?

As a developer we might have noticed that creation of some class is very difficult and number of time that we need to create. Such object creation every time is very expensive in terms of system resources. If we can cache that kind of object show how will surely boost the application performance and resource usage can be saved. This where object pool design pattern will help development community to cache the objects. Some time it is also called as Object cache or Resource cache design pattern.

It is adviced to keep all Reusable expensive objects that are not currently in use in the container so that they can be managed by one rational policy. To achieve this, the Reusable Pool class is designed to be a singleton class.

Support of C# for pooling objects

Queue Class

Queue is a Simple DataStucture which allows Add or Remove of Items at one of the ends only. It is basically called as First in First out data structure. The item which is added first is the first one to be removed. Default initial size of the queue is 32. Make sure that whenever Queue is initialized define the size of the queue, that Add and Remove operations are performed perfectly.

Enqueue () method will add the item in the last available portion and Dequeue () method will remove and return the oldest item in the queue. Set us see the code how it helps to implement the object pool design pattern.

EX: Simple Example

public class QueuedPool: Queue

       {

        public Person Fetch()

        {

            return (Person)Dequeue();

        }

 

        public void Store(Person person)

        {

            Enqueue(person);

        }

 

        public void ClearAll()

        {

            base.Clear();
        }
}

At client side

QueuedPool queuePool = new QueuedPool();
 queuePool.Store(new Person());

Person p = queuePool.Fetch();

EX: Using Generics

public interface IStore<T>

   {

        T Fetch();

        void Store(T obj);

        int Count { get;}

        void ClearAll();

}

public class QueuedPool<T> : Queue<T>, IStore<T>

   {

        public T Fetch()

        {

            return (T)Dequeue();

        }

        public void Store(T obj)

        {

            Enqueue(obj);

        }

        public void ClearAll()

        {

            base.Clear();

        }

}

At client side

QueuedPool<Person> queuePool = new QueuedPool<Person>();
queuePool.Store(new Person());
Person p = queuePool.Fetch();

EX: Thread safe Example

public sealed class ObjectPoolObject<T> where T : new()
        {
        private readonly int _poolSize;
        private readonly object _threadLocker;
        private readonly Queue<T> _poolManager;

        public ObjectPoolObject(int expectedPoolSize)
        {
            if (expectedPoolSize <= 0)
                throw new ArgumentOutOfRangeException("expectedPoolSize", "Pool size can't be null or zero or less than zero");

            _poolManager = new Queue<T>();
            _threadLocker = new object();
            _poolSize = expectedPoolSize;
        }

        public T Get()
        {
            lock (_threadLocker)
            {
                if (_poolManager.Count > 0)
                {
                     return _poolManager.Dequeue();
                }
                else
                {
                    return new T();
                }
            }
        }

        public int Count()
        {
            return _poolManager.Count;
        }

        public void Put(T obj)
        {
            lock(_threadLocker)
            {
                if (_poolManager.Count < _poolSize)
                    _poolManager.Enqueue(obj);
            }
         }
    }

At client side

ObjectPoolObject<Person> personPoolObject = new ObjectPoolObject<Person>(10);
Person a = personPoolObject.Get();
Person a1 = personPoolObject.Get();

addressPoolObject.Put(a);
addressPoolObject.Put(a1);

Best candidates for

1. Any ticketing counter, who goes first those, gets ticks first.
2. Who places order first they get served first.

Now let us continue with other options available in C#

Stack Class

The Stack class implements a Last in First Out data structure. The objects are stored in such a manner that the object added last is placed at the top of the stack.
Push () method adds new item to stack on the top of all items. Pop () method removes the top item in the items list.

public class StackPool<T>: Stack<T>, IStore<T>
{
        public T Fetch()
        {
            return Pop();
        }

        public void Store(T obj)
        {
            Push(obj);
        }

        public void ClearAll()
        {
            Clear();
        }
    }

At client

StackPool<Person> personStackPool = new StackPool<Person>();

personStackPool.Store(new Address());
personStackPool.Store(new Address());

Person p1 = personStackPool.Fetch();
Person p2 = personStackPool.Fetch();

Singleton Example

  public sealed class ObjectPoolObject<T> where T : new()
    {
        private readonly object _threadLocker = new object();
        private readonly Queue<T> _poolManager = new Queue<T>();
        private static ObjectPoolObject<T> _objectPoolObject;
        private ObjectPoolObject() { }

        static ObjectPoolObject()
        {
            _objectPoolObject = new ObjectPoolObject<T>();
        }

        public static ObjectPoolObject<T> GetInstance()
        {
            return _objectPoolObject;
        }

        public T Get()
        {
            lock (_threadLocker)
            {
                if (_poolManager.Count > 0)
                {
                     return _poolManager.Dequeue();
                }
                else
                {
                    return new T();
                }
            }
        }

        public int Count()
        {
            return _poolManager.Count;
        }

        public void Put(T obj)
        {
            lock(_threadLocker)
            {
                _poolManager.Enqueue(obj);
            }

         }
   }
 public class Person
   {
        private string _firstName;
        private string _middleInitial;
        private string _lastName;

        public string FirstName
        {
            get { return _firstName;}
            set { _firstName = value; }
        }
        public string MiddleInitial
        {
            get { return _middleInitial;}
            set { _middleInitial = value; }
        }
        public string LastName
        {
            get { return _lastName;}
            set { _lastName = value; }
        }
        public Person() { }
}