In the last post I discussed the Multiton pattern and this post continues the theme of non-GoF patterns by looking at Object Pool, another specialised Singleton. The purpose of this pattern is to re-use object instances to avoid creation / destruction. My mnemonic this time is a Car Pool which is just a collection of cars for my purposes:
public sealed class Car { public Car(string registration) { this.Registration = registration; } public string Registration { get; set; } public override string ToString() { return this.Registration; } }
The pool implementation also uses weak references to handle garbage collected cars which have not been explicitly returned to the pool:
using System; using System.Collections.Generic; using System.Linq; public sealed class CarPool { private static CarPool _pool = new CarPool(); private CarPool() { this.Cars = new Dictionary<Car, WeakReference>(); } public static int Availability { get { int value = 0; lock (_pool) { value = _pool.Cars.Where(x => null == x.Value || !x.Value.IsAlive).Count(); } return value; } } private Dictionary<Car, WeakReference> Cars { get; set; } public static void Add(params Car[] cars) { foreach (var car in cars) { lock (_pool) { _pool.Add(car); } } } public static Car Get() { Car result = null; if (0 < CarPool.Availability) { lock (_pool) { var item = _pool.Cars.Where(x => null == x.Value || !x.Value.IsAlive).FirstOrDefault(); var value = new WeakReference(item.Key); _pool.Cars[item.Key] = value; result = (Car)value.Target; } } return result; } public static void Return(Car car) { if (null == car) { throw new ArgumentNullException("car"); } lock (_pool) { _pool.Cars[car] = null; } } private void Add(Car car) { this.Cars.Add(car, new WeakReference(null)); } }
Here is a test which verifies the expected behaviour:
using Xunit; public sealed class ObjectPoolFacts { [Fact] public void car_pooling() { Car one = new Car("ABC 111"); Car two = new Car("ABC 222"); CarPool.Add(one, two); Car first = CarPool.Get(); Assert.Same(one, first); Car second = CarPool.Get(); Assert.Same(two, second); Assert.Null(CarPool.Get()); CarPool.Return(first); CarPool.Return(second); second = CarPool.Get(); Assert.Same(one, second); } }
No comments:
Post a Comment