implemented object pool pattern
This commit is contained in:
@@ -0,0 +1,67 @@
|
|||||||
|
from copy import deepcopy
|
||||||
|
from .singleton import Singleton
|
||||||
|
|
||||||
|
|
||||||
|
class Reusable(object):
|
||||||
|
"""
|
||||||
|
An abstract reusable class.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
Initialize a new Reusable instance.
|
||||||
|
"""
|
||||||
|
self.__state = deepcopy(self.__dict__)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""
|
||||||
|
Reset this objects state to the state that it was created with.
|
||||||
|
"""
|
||||||
|
self.__dict__ = deepcopy(self.__state)
|
||||||
|
self.__state = deepcopy(self.__dict__)
|
||||||
|
|
||||||
|
|
||||||
|
class Pool(object, metaclass=Singleton):
|
||||||
|
"""
|
||||||
|
An Object Pool design pattern implementation.
|
||||||
|
"""
|
||||||
|
def __init__(self, reusable_class, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Initialize a new object pool instance.
|
||||||
|
|
||||||
|
@param reusable_class: The reusable class this object pool is responsible for.
|
||||||
|
@param args: args for reusable object creation.
|
||||||
|
@param kwargs: kwargs for reusable object creation.
|
||||||
|
"""
|
||||||
|
self.reusables = list()
|
||||||
|
self.reusable_class = reusable_class
|
||||||
|
self.args = args
|
||||||
|
self.kwargs = kwargs
|
||||||
|
self.pool_size = 2
|
||||||
|
self._expand(self.pool_size)
|
||||||
|
|
||||||
|
def acquire(self):
|
||||||
|
"""
|
||||||
|
Acquire an object from the pool.
|
||||||
|
|
||||||
|
@return: An object from the pool.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
reusable = self.reusables.pop()
|
||||||
|
except IndexError:
|
||||||
|
self._expand(self.pool_size)
|
||||||
|
reusable = self.reusables.pop()
|
||||||
|
|
||||||
|
return reusable
|
||||||
|
|
||||||
|
def release(self, reusable):
|
||||||
|
"""
|
||||||
|
Release an object back into the pool.
|
||||||
|
|
||||||
|
@param reusable: The object to return to the pool.
|
||||||
|
"""
|
||||||
|
reusable.reset()
|
||||||
|
self.reusables.append(reusable)
|
||||||
|
|
||||||
|
def _expand(self, size):
|
||||||
|
for i in range(0, size):
|
||||||
|
self.reusables.append(self.reusable_class(*self.args, **self.kwargs))
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
from copy import deepcopy
|
||||||
|
from unittest import TestCase
|
||||||
|
from pypatterns.creational.pool import Reusable, Pool
|
||||||
|
|
||||||
|
|
||||||
|
class ReusableTestCase(TestCase):
|
||||||
|
"""
|
||||||
|
Unit testing class for the reusable class.
|
||||||
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Initialize testing data.
|
||||||
|
"""
|
||||||
|
class Dog(Reusable):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.sound = "woof"
|
||||||
|
super(Dog, self).__init__()
|
||||||
|
|
||||||
|
self.dog_class = Dog
|
||||||
|
|
||||||
|
def test_reset(self):
|
||||||
|
"""
|
||||||
|
Test the reset method.
|
||||||
|
|
||||||
|
@raise AssertionError: If the test fails.
|
||||||
|
"""
|
||||||
|
dog = self.dog_class()
|
||||||
|
original_state = deepcopy(dog.__dict__)
|
||||||
|
original_sound = dog.sound
|
||||||
|
dog.sound = "bark"
|
||||||
|
changed_sound = dog.sound
|
||||||
|
dog.reset()
|
||||||
|
reset_sound = dog.sound
|
||||||
|
dog.sound = "meow"
|
||||||
|
changed_sound_two = dog.sound
|
||||||
|
dog.reset()
|
||||||
|
reset_sound_two = dog.sound
|
||||||
|
dog.name = "george"
|
||||||
|
dog.reset()
|
||||||
|
final_state = deepcopy(dog.__dict__)
|
||||||
|
|
||||||
|
self.assertEquals("woof", original_sound)
|
||||||
|
self.assertEquals("bark", changed_sound)
|
||||||
|
self.assertEquals("woof", reset_sound)
|
||||||
|
self.assertEquals("meow", changed_sound_two)
|
||||||
|
self.assertEquals("woof", reset_sound_two)
|
||||||
|
self.assertEquals(original_state, final_state)
|
||||||
|
|
||||||
|
|
||||||
|
class PoolTestCase(TestCase):
|
||||||
|
"""
|
||||||
|
Unit testing class for the Pool class.
|
||||||
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Initialize testing data.
|
||||||
|
"""
|
||||||
|
class Dog(Reusable):
|
||||||
|
|
||||||
|
def __init__(self, sound, name):
|
||||||
|
self.sound = sound
|
||||||
|
self.name = name
|
||||||
|
super(Dog, self).__init__()
|
||||||
|
|
||||||
|
class DogPool(Pool):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(DogPool, self).__init__(Dog, 'woof', 'george')
|
||||||
|
|
||||||
|
self.dog_pool_class = DogPool
|
||||||
|
|
||||||
|
def test_acquire(self):
|
||||||
|
"""
|
||||||
|
Test the acquire method.
|
||||||
|
|
||||||
|
@raise AssertionError: If the test fails.
|
||||||
|
"""
|
||||||
|
dog_pool = self.dog_pool_class()
|
||||||
|
dog_one = dog_pool.acquire()
|
||||||
|
dog_two = dog_pool.acquire()
|
||||||
|
dog_three = dog_pool.acquire()
|
||||||
|
|
||||||
|
self.assertEquals(dog_one.__dict__, dog_two.__dict__, dog_three.__dict__)
|
||||||
|
self.assertNotEquals(id(dog_one), id(dog_two), id(dog_three))
|
||||||
|
|
||||||
|
def test_release(self):
|
||||||
|
"""
|
||||||
|
Test the release method.
|
||||||
|
|
||||||
|
@raise AssertionError: If the test fails.
|
||||||
|
"""
|
||||||
|
dog_pool = self.dog_pool_class()
|
||||||
|
|
||||||
|
dog_one = dog_pool.acquire()
|
||||||
|
dog_two = dog_pool.acquire()
|
||||||
|
dog_two.sound = 'meow'
|
||||||
|
|
||||||
|
dog_pool.release(dog_one)
|
||||||
|
dog_three = dog_pool.acquire()
|
||||||
|
self.assertEquals(id(dog_one), id(dog_three))
|
||||||
|
|
||||||
|
dog_pool.release(dog_two)
|
||||||
|
dog_four = dog_pool.acquire()
|
||||||
|
self.assertEquals(id(dog_two), id(dog_four))
|
||||||
|
|
||||||
|
self.assertEquals(dog_one.__dict__, dog_two.__dict__)
|
||||||
|
self.assertEquals(dog_three.__dict__, dog_four.__dict__)
|
||||||
|
self.assertEquals(dog_one.__dict__, dog_four.__dict__)
|
||||||
|
|
||||||
|
def test_singleton(self):
|
||||||
|
"""
|
||||||
|
Test that the pool class is a singleton
|
||||||
|
|
||||||
|
@raise AssertionError: If the test fails.
|
||||||
|
"""
|
||||||
|
dog_pool_one = self.dog_pool_class()
|
||||||
|
dog_pool_two = self.dog_pool_class()
|
||||||
|
|
||||||
|
class Cat(Reusable):
|
||||||
|
|
||||||
|
def __init__(self, sound, name):
|
||||||
|
self.sound = sound
|
||||||
|
self.name = name
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
class CatPool(Pool):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(Cat, 'meow', 'tom')
|
||||||
|
|
||||||
|
cat_pool_one = CatPool()
|
||||||
|
cat_pool_two = CatPool()
|
||||||
|
|
||||||
|
self.assertEquals(id(dog_pool_one), id(dog_pool_two))
|
||||||
|
self.assertEquals(id(cat_pool_one), id(cat_pool_two))
|
||||||
|
self.assertNotEquals(id(dog_pool_one), id(cat_pool_one))
|
||||||
Reference in New Issue
Block a user