Skip to content

Commit 5e5eefa

Browse files
committed
Update chain pattern with coroutine realization
1 parent 6993592 commit 5e5eefa

File tree

1 file changed

+104
-8
lines changed

1 file changed

+104
-8
lines changed

chain.py

Lines changed: 104 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@
22
# -*- coding: utf-8 -*-
33

44
"""http://www.testingperspective.com/wiki/doku.php/collaboration/chetan/designpatternsinpython/chain-of-responsibilitypattern"""
5+
"""http://www.dabeaz.com/coroutines/"""
6+
7+
import time
8+
import os
9+
import sys
10+
from contextlib import contextmanager
511

612
class Handler:
7-
def __init__(self,successor):
8-
self._successor = successor;
9-
def handle(self,request):
10-
i = self._handle(request)
11-
if not i:
13+
def __init__(self, successor=None):
14+
self._successor = successor
15+
def handle(self, request):
16+
res = self._handle(request)
17+
if not res:
1218
self._successor.handle(request)
1319
def _handle(self, request):
1420
raise NotImplementedError('Must provide implementation in subclass.')
@@ -43,16 +49,95 @@ def _handle(self, request):
4349

4450
class Client:
4551
def __init__(self):
46-
self.handler = ConcreteHandler1(ConcreteHandler3(ConcreteHandler2(DefaultHandler(None))))
52+
self.handler = ConcreteHandler1(ConcreteHandler3(ConcreteHandler2(DefaultHandler())))
4753
def delegate(self, requests):
4854
for request in requests:
4955
self.handler.handle(request)
5056

5157

58+
def coroutine(func):
59+
def start(*args, **kwargs):
60+
cr = func(*args, **kwargs)
61+
cr.next()
62+
return cr
63+
return start
64+
65+
@coroutine
66+
def coroutine1(target):
67+
while True:
68+
request = yield
69+
if 0 < request <= 10:
70+
print('request {} handled in coroutine 1'.format(request))
71+
else:
72+
target.send(request)
73+
74+
@coroutine
75+
def coroutine2(target):
76+
while True:
77+
request = yield
78+
if 10 < request <= 20:
79+
print('request {} handled in coroutine 2'.format(request))
80+
else:
81+
target.send(request)
82+
83+
@coroutine
84+
def coroutine3(target):
85+
while True:
86+
request = yield
87+
if 20 < request <= 30:
88+
print('request {} handled in coroutine 3'.format(request))
89+
else:
90+
target.send(request)
91+
92+
@coroutine
93+
def default_coroutine():
94+
while True:
95+
request = yield
96+
print('end of chain, no coroutine for {}'.format(request))
97+
98+
class ClientCoroutine:
99+
def __init__(self):
100+
self.target = coroutine1(coroutine3(coroutine2(default_coroutine())))
101+
102+
def delegate(self, requests):
103+
for request in requests:
104+
self.target.send(request)
105+
106+
def timeit(func):
107+
108+
def count(*args, **kwargs):
109+
start = time.time()
110+
res = func(*args, **kwargs)
111+
count._time = time.time() - start
112+
return res
113+
return count
114+
115+
@contextmanager
116+
def suppress_stdout():
117+
try:
118+
stdout, sys.stdout = sys.stdout, open(os.devnull, 'w')
119+
yield
120+
finally:
121+
sys.stdout = stdout
122+
123+
52124
if __name__ == "__main__":
53-
client = Client()
125+
client1 = Client()
126+
client2 = ClientCoroutine()
54127
requests = [2, 5, 14, 22, 18, 3, 35, 27, 20]
55-
client.delegate(requests)
128+
129+
client1.delegate(requests)
130+
print('-'*30)
131+
client2.delegate(requests)
132+
133+
requests *= 10000
134+
client1_delegate = timeit(client1.delegate)
135+
client2_delegate = timeit(client2.delegate)
136+
with suppress_stdout():
137+
client1_delegate(requests)
138+
client2_delegate(requests)
139+
# lets check what is faster
140+
print(client1_delegate._time, client2_delegate._time)
56141

57142
### OUTPUT ###
58143
# request 2 handled in handler 1
@@ -64,3 +149,14 @@ def delegate(self, requests):
64149
# end of chain, no handler for 35
65150
# request 27 handled in handler 3
66151
# request 20 handled in handler 2
152+
# ------------------------------
153+
# request 2 handled in coroutine 1
154+
# request 5 handled in coroutine 1
155+
# request 14 handled in coroutine 2
156+
# request 22 handled in coroutine 3
157+
# request 18 handled in coroutine 2
158+
# request 3 handled in coroutine 1
159+
# end of chain, no coroutine for 35
160+
# request 27 handled in coroutine 3
161+
# request 20 handled in coroutine 2
162+
# (0.2369999885559082, 0.16199994087219238)

0 commit comments

Comments
 (0)