I am exploring different concepts in python and I happened to read upon an example of coroutines which can be used for the chain of responsibility design pattern. I wrote the following code:
from functools import wraps
def coroutine(function):
@wraps(function)
def wrapper(*args, **kwargs):
generator = function(*args, **kwargs)
next(generator)
return generator
return wrapper
@coroutine
def PlatinumCustomer(successor=None):
cust = (yield)
if cust.custtype == 'platinum':
print "Platinum Customer"
elif successor is not None:
successor.send(cust)
@coroutine
def GoldCustomer(successor=None):
cust = (yield)
if cust.custtype == 'gold':
print "Gold Customer"
elif successor is not None:
successor.send(cust)
@coroutine
def SilverCustomer(successor=None):
cust = (yield)
if cust.custtype == 'silver':
print "Silver Customer"
elif successor is not None:
successor.send(cust)
@coroutine
def DiamondCustomer(successor=None):
cust = (yield)
if cust.custtype == 'diamond':
print "Diamond Customer"
elif successor is not None:
successor.send(cust)
class Customer:
pipeline = PlatinumCustomer(GoldCustomer(SilverCustomer(DiamondCustomer())))
def __init__(self,custtype):
self.custtype = custtype
def HandleCustomer(self):
try:
self.pipeline.send(self)
except StopIteration:
pass
if __name__ == '__main__':
platinum = Customer('platinum')
gold = Customer('gold')
silver = Customer('silver')
diamond = Customer('diamond')
undefined = Customer('undefined')
platinum.HandleCustomer()
gold.HandleCustomer()
undefined.HandleCustomer()
What I have tried to do here is try to create a chain of responsibility pattern solution for handling different types of customers (Platinum, Gold, Diamond, Silver).
For that Customer has a pipeline where I have mentioned the order in which the different customers will be handled. Customer().HandleCustomer will send an instance of itself through the pipeline which will check whether its custtype matches and then process it accordingly or it will send it across to its successor (if available)
PROBLEM: The problem is that when I run the above script, it will handle the first platinum customer but not the gold or the undefined. I am assuming this is because he has reached the end of the generator. How do I modify the code so that everytime it is a new instance of a customer, it will go through the pipeline from its beginning?
Your coroutines must loop forever in order to handle successive calls, as in:
@coroutine
def PlatinumCustomer(successor=None):
while 1: # <---- this is missing from your coroutines
cust = (yield)
if cust.custtype == 'platinum':
print "Platinum Customer"
elif successor is not None:
successor.send(cust)
And to handle the 'undefined' type, you'll need a final catch-all handler:
@coroutine
def UndefinedCustomer():
while 1:
cust = (yield)
print "No such customer type '%s'" % cust.custtype
and add it to your pipeline:
pipeline = PlatinumCustomer(GoldCustomer(SilverCustomer(DiamondCustomer(UndefinedCustomer()))))
(A terminating UndefinedCustomer handler also will allow you to remove the 'if there is no successor' code from your coroutines - all will have successors except for the terminator, which knows that it is the terminator and will not call a successor.)
With these changes, I get this output from your tests:
Platinum Customer
Gold Customer
No such customer type 'undefined'
Also, why the catch for StopIteration in HandleCustomer? This code should be sufficient:
def HandleCustomer(self):
self.pipeline.send(self)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With