BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Design Patterns
.NET 2.0+

Object Pool Design Pattern

The object pool pattern is a creational design pattern that can improve performance when working with classes that are slow to instantiate. Rather than constructing new objects, reusable objects are retrieved from, and released to, a pool as required.

Example Object Pool

In this section we'll create an example program using the object pool design pattern. The example simulates a system for automatic picking in a warehouse. The building has five automatic picking robots, each represented by an object in a pool. You could imagine that the objects are slow to create and that the object pool good give a performance advantage. In reality this would be offset by the fact that the picking process would be slow. However, the pool ensures that the system cannot over-allocated robots; if a sixth active automatic picker is requested it throws an exception.

We'll start with the AutomaticPicker class. This is the pooled type that represents our robot pickers. Each picker has an identifying number, accessible via the PickerId property. We could use this if there was a breakdown to identify the faulty robot. The picker also knows its current location in the warehouse and what it is carrying.

The class includes several methods. Identify allows us to determine which robot an object reference is connected to. GoToLocation instructs a robot to move through the warehouse. In this example we aren't simulating the time taken for the robot to move. Instead we are just outputting a message indicating the activity. Pick and Drop tell the automated picker to pick up an item from the current location or drop what it is carrying. This is far too simplistic for a real system but enough to demonstrate the design pattern.

The code for the class is as follows:

public class AutomatedPicker
{
    public AutomatedPicker(int pickerId)
    {
        PickerId = pickerId;
        CurrentLocation = "Recharging Station";
    }

    public int PickerId { get; private set; }

    public string CurrentLocation { get; private set; }

    public string Carrying { get; private set; }

    public void Identify(string code)
    {
        ShowMessage("Identified as " + code);
    }

    public void GoToLocation(string location)
    {
        CurrentLocation = location;
        ShowMessage("At " + location);
    }

    public void Pick(string item)
    {
        Carrying = item;
        ShowMessage("Picked Up " + item);
    }

    public void Drop()
    {
        ShowMessage("Dropped " + Carrying);
        Carrying = null;
    }

    public void ShowMessage(string msg)
    {
        Console.WriteLine("Picker {0} : {1}", PickerId, msg);
    }
}

We can now create the object pool in the PickerPool class. The code is very similar to the basic pattern code you saw earlier. There are a few points worthy of note. The first is that the list of AutomatedPickers is populated in the class's static constructor. New objects will never be created. If the pool is exhausted and another robot is required, the GetPicker method throws an InvalidOperationException. Secondly, the ReleasePicker method, which releases an object back to the pool, sends an instruction to the robot to drop any item it is carrying and return to the battery recharging station.

public static class PickerPool
{
    const int PickerCount = 5;

    private static List<AutomatedPicker> _available = new List<AutomatedPicker>();
    private static List<AutomatedPicker> _inUse = new List<AutomatedPicker>();

    static PickerPool()
    {
        for (int i = 1; i <= PickerCount; i++)
        {
            _available.Add(new AutomatedPicker(i));
        }
    }

    public static AutomatedPicker GetPicker()
    {
        lock (_available)
        {
            if (_available.Count != 0)
            {
                AutomatedPicker picker = _available[0];
                _inUse.Add(picker);
                _available.RemoveAt(0);
                return picker;
            }
            else
            {
                throw new InvalidOperationException("No pickers are available");
            }
        }
    }

    public static void ReleasePicker(AutomatedPicker picker)
    {
        Reset(picker);

        lock (_available)
        {
            _available.Add(picker);
            _inUse.Remove(picker);
        }
    }

    private static void Reset(AutomatedPicker picker)
    {
        if (picker.Carrying != null)
        {
            picker.Drop();
        }

        picker.GoToLocation("Recharging Station");
    }
}
30 June 2013