5

我正在探索 python 中的不同概念,并且碰巧阅读了一个可用于责任链设计模式的协程示例。我写了以下代码:

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()   

我在这里尝试做的是尝试创建一个责任链模式解决方案来处理不同类型的客户(白金、黄金、钻石、白银)。

因为那个客户有一个管道,我已经提到了处理不同客户的顺序。Customer().HandleCustomer 将通过管道发送一个自身的实例,该管道将检查其 custtype 是否匹配,然后进行相应处理,或者将其发送给其继任者(如果可用)

问题:问题是当我运行上面的脚本时,它将处理第一个白金客户,而不是黄金或未定义的客户。我假设这是因为他已经到了发电机的尽头。如何修改代码,以便每次它是客户的新实例时,它都会从一开始就通过管道?

4

1 回答 1

8

您的协程必须永远循环才能处理连续调用,如下所示:

@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)

要处理“未定义”类型,您需要一个最终的包罗万象的处理程序:

@coroutine
def UndefinedCustomer():
    while 1:
        cust = (yield)
        print "No such customer type '%s'" % cust.custtype

并将其添加到您的管道中:

pipeline = PlatinumCustomer(GoldCustomer(SilverCustomer(DiamondCustomer(UndefinedCustomer()))))

(终止的 UndefinedCustomer 处理程序还允许您从协程中删除“如果没有后继者”代码 - 除了终止符之外,所有代码都有后继者,终止符知道它是终止符并且不会调用后继者。)

通过这些更改,我从您的测试中得到以下输出:

Platinum Customer
Gold Customer
No such customer type 'undefined'

另外,为什么要在 HandleCustomer 中捕获 StopIteration?这段代码应该足够了:

def HandleCustomer(self):
    self.pipeline.send(self)
于 2015-02-23T07:07:07.730 回答