Implemented Decorator Pattern.

This commit is contained in:
tylerlaberge
2016-08-20 13:03:30 -04:00
parent 9a6dc2b27c
commit e59f84105b
2 changed files with 113 additions and 21 deletions

View File

@@ -3,31 +3,71 @@ from abc import ABCMeta, abstractmethod
class Decorator(object, metaclass=ABCMeta):
"""
Base Decorator class that all decorator classes inherit from.
"""
def __get__(self, instance, owner):
"""
Override __get__ in order to get the instance of a bound of method call.
"""
return partial(self.__call__, instance)
@abstractmethod
def __call__(self, *args, **kwargs):
"""
All decorators must implement a __call__ method.
"""
pass
class DecoratorSimple(Decorator, metaclass=ABCMeta):
"""
A Base Decorator class for decorators with no arguments.
"""
def __init__(self, func):
"""
Initialize a new DecoratorSimple instance.
@param func: The function being decorated.
"""
self.func = func
class DecoratorArgs(Decorator, metaclass=ABCMeta):
class DecoratorComplex(Decorator, metaclass=ABCMeta):
"""
A Base Decorator class for decorators with arguments.
"""
@abstractmethod
def __init__(self, *args, **kwargs):
"""
Initialize a new DecoratorComplex instance.
@param args: Args for the decorator.
@param kwargs: Keyword args for the decorator.
"""
pass
@abstractmethod
def __call__(self, func, *args, **kwargs):
"""
Concrete DecoratorComplex instances must override the __call__ method.
@param func: The function being decorated.
@param args: Arguments for the decorated function.
@param kwargs: Keyword arguments for the decorated function.
@return:
"""
pass
class Wrap(DecoratorSimple):
class CallWrapper(DecoratorSimple):
"""
A Decorator for wrapping DecoratorComplex __call__ methods.
"""
def __call__(self, instance, func):
"""
Wrap a concrete DecoratorComplex __call__ method.
"""
def wrapped(*args, **kwargs):
return self.func(instance, func, *args, **kwargs)

View File

@@ -1,6 +1,6 @@
import time
from unittest import TestCase
from pypatterns.structural.decorator import DecoratorSimple, DecoratorArgs, Wrap
from pypatterns.structural.decorator import DecoratorSimple, DecoratorComplex, CallWrapper
class DecoratorSimpleTestCase(TestCase):
@@ -51,20 +51,20 @@ class DecoratorSimpleTestCase(TestCase):
self.assertAlmostEqual(2.0, slow_function.end, delta=1.0)
class DecoratorArgsTestCase(TestCase):
class DecoratorComplexTestCase(TestCase):
"""
Unit testing class for the DecoratorArgs class.
Unit testing class for the DecoratorComplex class.
"""
def setUp(self):
"""
Initialize testing data.
"""
class Alert(DecoratorArgs):
class Alert(DecoratorComplex):
def __init__(self, alert_time):
self.alert_time = alert_time
@Wrap
@CallWrapper
def __call__(self, func, *args, **kwargs):
start = time.time()
return_val = func(*args, **kwargs)
@@ -81,12 +81,20 @@ class DecoratorArgsTestCase(TestCase):
@raise AssertionError: If the test fails.
"""
@self.alert(1)
def slow_function():
time.sleep(2)
return 'foo'
class SlowClass(object):
self.assertEquals(('foo', True), slow_function())
@self.alert(1)
def slow_function_true(self):
time.sleep(2)
return 'foo'
@self.alert(1)
def slow_function_false(self):
return 'bar'
slow_class = SlowClass()
self.assertEquals(('foo', True), slow_class.slow_function_true())
self.assertEquals(('bar', False), slow_class.slow_function_false())
def test_decorate_args(self):
"""
@@ -95,9 +103,53 @@ class DecoratorArgsTestCase(TestCase):
@raise AssertionError: If the test fails.
"""
@self.alert(1)
def slow_function(n):
time.sleep(n)
return 'foo'
class SlowClass(object):
self.assertEquals(('foo', True), slow_function(2))
@self.alert(1)
def slow_function_true(self, n):
time.sleep(n)
return 'foo'
@self.alert(1)
def slow_function_false(self, n):
return n
slow_class = SlowClass()
self.assertEquals(('foo', True), slow_class.slow_function_true(2))
self.assertEquals((10, False), slow_class.slow_function_false(10))
class WrapTestCase(TestCase):
"""
Unit testing class for the CallWrapper decorator class.
"""
def test_wrap(self):
"""
Test the wrap decorator
@raise AssertionError: If the test fails.
"""
class SlowClass(DecoratorComplex):
def __init__(self, sleep_time):
self.sleep_time = sleep_time
self.end_time = None
@CallWrapper
def __call__(self, func, *args, **kwargs):
start_time = time.time()
return_val = func(*args, **kwargs)
time.sleep(self.sleep_time)
end_time = time.time() - start_time
self.end_time = end_time
return return_val, self.sleep_time, self.end_time
@SlowClass(1)
def hello_world(n):
return ['hello world' for _ in range(n)]
return_val, sleeptime, end_time = hello_world(5)
self.assertEquals(1, sleeptime)
self.assertAlmostEquals(1, end_time, delta=1)
self.assertListEqual(['hello world' for _ in range(5)], return_val)