我不是第一个希望本书有Python版本的人,但是我认为编写Python代码将是一个很棒的练习。
我ve尝试在下面的Python“ Head First设计模式”第1章中实现策略设计模式。现在,我知道Python在一般意义上不是Java,但从本质上来说并不是。因此,我敢肯定我可以对这段代码做更多的Python事情。
也许我们可以使用内置的Python
Duck
实现set_fly_behavior()
类set_quack_behavior()
和property
。 还有其他建议吗?
#!/usr/bin/env python
################################################################################
# Abstract Duck class and concrete Duck type classes.
################################################################################
class Duck(object):
def __init__(self):
pass
def set_fly_behavior(self, fb):
self.fly_behavior = fb
def set_quack_behavior(self, qb):
self.quack_behavior = qb
def perform_fly(self):
self.fly_behavior.fly()
def perform_quack(self):
self.quack_behavior.quack()
def swim(self):
print "All ducks float, even decoys!"
class MallardDuck(Duck):
def __init__(self):
Duck.__init__(self)
fly_instance = Fly()
self.set_fly_behavior(fly_instance)
quack_instance = Quack()
self.set_quack_behavior(quack_instance)
print "I'm a real Mallard Duck"
class ModelDuck(Duck):
def __init__(self):
Duck.__init__(self)
fly_no_way_instance = FlyNoWay()
self.set_fly_behavior(fly_no_way_instance)
squeak_instance = SqueakQuack()
self.set_quack_behavior(squeak_instance)
print "I'm a Model Duck"
class DecoyDuck(Duck):
def __init__(self):
Duck.__init__(self)
fly_no_way_instance = FlyNoWay()
self.set_fly_behavior(fly_no_way_instance)
mute_instance = MuteQuack()
self.set_quack_behavior(mute_instance)
print "I'm a Decoy Duck"
################################################################################
# Fly behavior interface and behavior implementation classes.
################################################################################
class FlyBehavior():
def __init__(self):
pass
class Fly(FlyBehavior):
def fly(self):
print "I'm flying!!"
class FlyNoWay(FlyBehavior):
def fly(self):
print "I can't fly"
class FlyRocketPowered(FlyBehavior):
def fly(self):
print "I'm flying with a rocket!"
################################################################################
# Quack behavior interface and behavior implementation classes.
################################################################################
class QuackBehavior():
def __init__(self):
pass
class Quack(QuackBehavior):
def quack(self):
print "Quack"
class MuteQuack(QuackBehavior):
def quack(self):
print "<< Silence >>"
class SqueakQuack(QuackBehavior):
def quack(self):
print "Squeak"
################################################################################
# Test Code.
################################################################################
if __name__ == "__main__":
print '#'*80
print "Mallard Duck"
print '#'*80
mallard = MallardDuck()
mallard.perform_quack()
mallard.perform_fly()
print '#'*80
print "Model Duck"
print '#'*80
model = ModelDuck()
model.perform_fly()
fly_rocket_powered_instance = FlyRocketPowered()
model.set_fly_behavior(fly_rocket_powered_instance)
model.perform_fly()
print '#'*80
print "Decoy Duck"
print '#'*80
decoy = DecoyDuck()
decoy.perform_fly()
decoy.perform_quack()
#1 楼
_details
中的魔鬼您的建议不错,但您不需要财产;您可以只使用普通属性。 setter所做的全部工作就是设置变量,因此只需进行设置即可。所以,这个:
self.set_fly_behavior(fly_instance)
可以变成这个:
self._fly_behaviour = fly_instance
注意我对
self._fly_behaviour
的使用。由于它是该类的实现细节,因此最佳实践是在变量名称前添加下划线。这可以告诉程序员,它不是设计用于外部的。此外:命名行为
名称
perform_quack()
和perform_fly()
完全不是Pythonic的。为什么不只是quack()
和fly()
?表演并没有告诉我们任何东西,除了可能将实现细节泄漏到外部(这些委托)。调用者不需要关心这件事。ABCs
除此之外,您还可以创建基类Abstract Base Classs:
from abc import ABCMeta, abstractmethod
...
class QuackBehavior(object):
__metaclass__ = ABCMeta
@abstractmethod
def quack(self):
pass
@classmethod
def __subclasshook__(cls, Check):
required = ["quack"]
rtn = True
for r in required:
if not any(r in vars(BaseClass) for BaseClass in Check.__mro__):
rtn = NotImplemented
return rtn
这使您可以为类提供更多的Pythonic接口。
(还请注意,删除了空的构造函数。Python还是提供了一个空的构造函数,因此,如果您不对其进行任何操作,请不要麻烦定义它。这只是无用的额外代码。)
一种功能性方法
这是一个非常强大的Python解决方案。如果您知道这些行为始终只是一个函数,那么我会认为不需要类。
相反,请记住Python函数是一流的对象:
def quack(self):
print("Quack")
def mute_quack(self):
print "<< Silence >>"
some_duck = Duck()
some_duck.quack = mute_quack
混合方法
我们可以做一个小的修改:通过使用属性将函数转换为方法,以便可以正常调用它们。
(我假设您需要访问方法中的
self
;如果不需要,则忽略该参数,它将像静态方法一样按原样工作。)import types
class Duck(object):
...
@property
def fly(self):
return self._fly
@fly.setter
def fly(self, value):
self._fly = types.MethodType(value, self)
@property
def quack(self):
return self._quack
@quack.setter
def quack(self, value):
self._quack = types.MethodType(value, self)
再走一步...
嗯...我们对两个属性都做同样的事情。如果需要,我们可以更进一步。
让我们对其进行概括:
import types
def method_property(name):
def getter(self):
return getattr(self, name)
def setter(self, value):
setattr(self, name, types.MethodType(value, self))
return getter, setter
class Duck(object):
...
quack = property(*method_property("_quack"))
fly = property(*method_property("_fly"))
仅根据需要分配功能-也许在子类的构造函数中。显然,如果您需要更复杂的行为,则可能不需要。但对于简单的事情,我会说这是更好的解决方案。所有子类都为其分配它们,这对于构造函数来说很有意义:
class Duck(object):
def __init__(self, fly, quack):
self.fly = fly
self.quack = quack
...
class ModelDuck(Duck):
def __init__(self):
Duck.__init__(self, fly_no_way, squeak_quack)
print "I'm a Model Duck"
或者,如果您使用的是原始类的实现:
class Duck(object):
def __init__(self, fly, quack):
self._fly_behaviour = fly
self._quack_behaviour = quack
...
class ModelDuck(Duck):
def __init__(self):
Duck.__init__(self, FlyNoWay(), SqueakQuack())
print "I'm a Model Duck"
结论
如果将所有这些包装在一起,我们将得到两个实现:
基于函数,并且
基于类。
这些实现消除了重复,将使这种事情在Python整体上更容易使用。
评论
\ $ \ begingroup \ $
哇,谢谢你这么详细的答复。一旦获得足够的代表,我将确保为您+1。同时,您已经给了我很多参考资料,可以应用于我的编程。我还将继续从Head First本书继续研究更多的设计模式。请注意:)
\ $ \ endgroup \ $
– PythonJin
13年1月19日在23:01
\ $ \ begingroup \ $
我仍然在这里添加一些代码。对于基于类的实现,我正在尝试获取__subclasshook__的句柄。在抽象行为中,我们将内置的__subclasshook__定义为函数subclasshook的类方法,该方法在代码顶部定义。因此内置的classmethod应该返回函数subclasshook的Class。但是我认为__subclasshook__只能返回True,False或NotImplemented。由于代码有效,我当然会缺少一些东西。
\ $ \ endgroup \ $
– PythonJin
2013年1月20日12:37
\ $ \ begingroup \ $
另外,在顶部函数subclasshook(requried)的for循环中,我不太了解这里的逻辑。我的问题是如果没有的话(在Check .__ mro__中为BaseClass的vars(BaseClass)中的r):.变量r是需要在每种具体行为中实现的抽象方法的名称。因此,在这里,我们检查具体类的__mro__及其所有基类(?),以获取必须实现的抽象方法的名称。我们是否应该检查该方法是否位于__mro__的每个类中,而不仅是每个类?
\ $ \ endgroup \ $
– PythonJin
13年1月20日在12:52
\ $ \ begingroup \ $
@PythonJin为了回应您的第一个评论,subclasshook()返回一个函数,因此当我们调用__subclasshook__ = classmethod(subclasshook([“ fly”]))时,Python会评估subclasshook()调用,并给出classmethod( )返回True,False或NotImplemented作为第一个参数的函数。它不会传递classmethod()到subclasshook()函数本身,而只是传递它返回的值(恰好是另一个函数)。然后,它使其成为一个类方法,并将其分配给__subclasshook__。
\ $ \ endgroup \ $
–漂亮
2013年1月20日16:11
\ $ \ begingroup \ $
@PythonJin为了回应第二点,请考虑调用函数时Python的工作方式。它查找您在该类中调用的函数,如果找不到该函数,则会处理MRO(这是所有基类,并且已按一定顺序删除了重复项-由于Python支持多重继承,所以这不是琐碎的)并检查它,直到找到它为止。如果我们检查它是否在所有类中,那么如果不将其添加到子类中就不可能将其添加到基类中。
\ $ \ endgroup \ $
–漂亮
13年1月20日在16:13