Implemented Flyweight design pattern.
This commit is contained in:
43
pypatterns/structural/flyweight.py
Normal file
43
pypatterns/structural/flyweight.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
class FlyweightMeta(type):
|
||||||
|
"""
|
||||||
|
Flyweight meta class as part of the Flyweight design pattern.
|
||||||
|
"""
|
||||||
|
def __new__(mcs, name, bases, attrs):
|
||||||
|
"""
|
||||||
|
Override class construction to add 'pool' attribute to classes dict.
|
||||||
|
@param name: The name of the class.
|
||||||
|
@param bases: Base classes of the class.
|
||||||
|
@param attrs: Attributes of the class.
|
||||||
|
@return: A new Class.
|
||||||
|
"""
|
||||||
|
attrs['pool'] = dict()
|
||||||
|
return super(FlyweightMeta, mcs).__new__(mcs, name, bases, attrs)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _serialize_params(cls, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Serialize input parameters to a key.
|
||||||
|
Simple implementation is just to serialize it as a string
|
||||||
|
"""
|
||||||
|
args_list = [str(arg) for arg in args]
|
||||||
|
args_list.extend([str(kwargs), cls.__name__])
|
||||||
|
key = ''.join(args_list)
|
||||||
|
return key
|
||||||
|
|
||||||
|
def __call__(cls, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Override call to use objects from a pool if identical parameters are used for object creation.
|
||||||
|
|
||||||
|
@param args: Arguments for class instantiation.
|
||||||
|
@param kwargs: Keyword arguments for class instantiation.
|
||||||
|
@return: A new instance of the class.
|
||||||
|
"""
|
||||||
|
key = FlyweightMeta._serialize_params(cls, *args, **kwargs)
|
||||||
|
pool = getattr(cls, 'pool', {})
|
||||||
|
|
||||||
|
instance = pool.get(key)
|
||||||
|
if not instance:
|
||||||
|
instance = super(FlyweightMeta, cls).__call__(*args, **kwargs)
|
||||||
|
pool[key] = instance
|
||||||
|
|
||||||
|
return instance
|
||||||
32
tests/structural_tests/test_flyweight.py
Normal file
32
tests/structural_tests/test_flyweight.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from unittest import TestCase
|
||||||
|
from pypatterns.structural.flyweight import FlyweightMeta
|
||||||
|
|
||||||
|
|
||||||
|
class FlyweightMetaTestCase(TestCase):
|
||||||
|
"""
|
||||||
|
Unit testing class for the FlyweightMeta class.
|
||||||
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Initialize testing data.
|
||||||
|
"""
|
||||||
|
class Card(object, metaclass=FlyweightMeta):
|
||||||
|
|
||||||
|
def __init__(self, suit, value):
|
||||||
|
self.suit = suit
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
self.card_class = Card
|
||||||
|
|
||||||
|
def test_flyweight(self):
|
||||||
|
"""
|
||||||
|
Test that new objects with the same params are actually equal.
|
||||||
|
|
||||||
|
@raise AssertionError: If the test fails.
|
||||||
|
"""
|
||||||
|
three_of_spades = self.card_class('Spade', 3)
|
||||||
|
four_of_spades = self.card_class('Spade', 4)
|
||||||
|
three_of_spades_two = self.card_class('Spade', 3)
|
||||||
|
|
||||||
|
self.assertEqual(id(three_of_spades), id(three_of_spades_two))
|
||||||
|
self.assertNotEqual(id(three_of_spades), id(four_of_spades))
|
||||||
Reference in New Issue
Block a user