通过工厂函数对 __init__() 加以利用
我们可以通过工厂函数来构建一副完整的扑克牌。这会比枚举所有52张扑克牌要好得多,在Python中,我们有如下两种常见的工厂方法:
定义一个函数,该函数会创建所需类的对象。 定义一个类,该类有创建对象的方法。这是一个完整的工厂设计模式,正如设计模式书所描述的那样。在诸如Java这样的语言中,工厂类层次结构是必须的,因为该语言不支持独立的函数。 在Python中,类并不是必须的。只是当有相关的工厂非常复杂的时候才会显现出优势。Python的优势就是当一个简单的函数可以做的更好的时候我们决不强迫使用类层次结构。 虽然这是一本关于面向对象编程的书,但函数真是一个好东西。这在Python中是常见的也是最地道的。如果需要的话,我们总是可以将一个函数重写为适当的可调用对象。我们可以将一个可调用对象重构到我们的工厂类层次结构中。我们将在第五章《使用可调用对象和上下文》中学习可调用对象。
一般,类定义的优点是通过继承实现代码重用。工厂类的函数就是包装一些目标类层次结构和复杂对象的构造。如果我们有一个工厂类,当扩展目标类层次结构的时候,我们可以添加子类到工厂类中。这给我们提供了多态性工厂类;不同的工厂类定义具有相同的方法签名,可以交替使用。
这类水平的多态性对于静态编译语言如Java或C++非常有用。编译器可以解决类和方法生成代码的细节。
如果选择的工厂定义不能重用任何代码,则在Python中类层次结构不会有任何帮助。我们可以简单的使用具有相同签名的函数。
以下是我们各种Card子类的工厂函数:
def card(rank, suit): if rank == 1: return AceCard('A', suit) elif 2 <= rank < 11: return NumberCard(str(rank), suit) elif 11 <= rank < 14: name = {11: 'J', 12: 'Q', 13: 'K' }[rank] return FaceCard(name, suit) else: raise Exception("Rank out of range")
这个函数通过数值类型的rank和suit对象构建Card类。我们现在可以非常简单的构建牌了。我们已经封装构造问题到一个单一的工厂函数中,允许应用程序在不知道精确的类层次结构和多态设计是如何工作的情况下进行构建。
下面是一个如何通过这个工厂函数构建一副牌的示例:
deck = [card(rank, suit) for rank in range(1,14) for suit in (Club, Diamond, Heart, Spade)]
它枚举了所有的牌值和花色来创建完整的52张牌。
1. 错误的工厂设计和模糊的else子句
注意card()函数里面的if语句结构。我们没有使用“包罗万象”的else子句来做任何处理;我们只是抛出异常。使用“包罗万象”的else子句会引出一个小小的辩论。
新闻热点
疑难解答