nop*_*ole 37 python design-patterns
在2009年维基百科的战略模式条目中,有一个用PHP编写的例子.
大多数其他代码示例执行以下操作:
a = Context.new(StrategyA.new)
a.execute #=> Doing the task the normal way
b = Context.new(StrategyB.new)
b.execute #=> Doing the task alternatively
c = Context.new(StrategyC.new)
c.execute #=> Doing the task even more alternative
Run Code Online (Sandbox Code Playgroud)
在Python代码中,使用不同的技术和Submit按钮.我想知道如果Python代码也按照其他代码示例的方式执行它会是什么样子.
更新:使用Python中的第一类函数可以更短吗?
e-s*_*tis 67
Python中的示例与其他示例没有太大区别.要模拟PHP脚本:
class StrategyExample:
def __init__(self, func=None):
if func:
self.execute = func
def execute(self):
print("Original execution")
def executeReplacement1():
print("Strategy 1")
def executeReplacement2():
print("Strategy 2")
if __name__ == "__main__":
strat0 = StrategyExample()
strat1 = StrategyExample(executeReplacement1)
strat2 = StrategyExample(executeReplacement2)
strat0.execute()
strat1.execute()
strat2.execute()
Run Code Online (Sandbox Code Playgroud)
输出:
Original execution
Strategy 1
Strategy 2
Run Code Online (Sandbox Code Playgroud)
主要区别是:
if func == None
可以使用该模式).请注意,有三种方法可以在Python中动态添加方法:
我告诉你的方式.但是该方法将是静态的,它不会传递"自我"参数.
使用班级名称:
StrategyExample.execute = func
这里,所有实例都将func
作为execute
方法获取,并将self
作为参数传递.
仅绑定到实例(使用types
模块):
strat0.execute = types.MethodType(executeReplacement1, strat0)
或者使用Python 2,还需要更改实例的类:
strat0.execute = types.MethodType(executeReplacement1, strat0,
StrategyExample)
这将绑定新方法strat0
,并且仅strat0
与第一个示例绑定.但是作为一个论点start0.execute()
会被self
传递.
如果需要在函数中使用对当前实例的引用,那么您将组合第一个和最后一个方法.如果你不:
class StrategyExample:
def __init__(self, func=None):
self.name = "Strategy Example 0"
if func:
self.execute = func
def execute(self):
print(self.name)
def executeReplacement1():
print(self.name + " from execute 1")
def executeReplacement2():
print(self.name + " from execute 2")
if __name__ == "__main__":
strat0 = StrategyExample()
strat1 = StrategyExample(executeReplacement1)
strat1.name = "Strategy Example 1"
strat2 = StrategyExample(executeReplacement2)
strat2.name = "Strategy Example 2"
strat0.execute()
strat1.execute()
strat2.execute()
Run Code Online (Sandbox Code Playgroud)
你会得到:
Traceback (most recent call last):
File "test.py", line 28, in <module>
strat1.execute()
File "test.py", line 13, in executeReplacement1
print self.name + " from execute 1"
NameError: global name 'self' is not defined
Run Code Online (Sandbox Code Playgroud)
所以正确的代码是:
import sys
import types
if sys.version_info[0] > 2: # Python 3+
create_bound_method = types.MethodType
else:
def create_bound_method(func, obj):
return types.MethodType(func, obj, obj.__class__)
class StrategyExample:
def __init__(self, func=None):
self.name = "Strategy Example 0"
if func:
self.execute = create_bound_method(func, self)
def execute(self):
print(self.name)
def executeReplacement1(self):
print(self.name + " from execute 1")
def executeReplacement2(self):
print(self.name + " from execute 2")
if __name__ == "__main__":
strat0 = StrategyExample()
strat1 = StrategyExample(executeReplacement1)
strat1.name = "Strategy Example 1"
strat2 = StrategyExample(executeReplacement2)
strat2.name = "Strategy Example 2"
strat0.execute()
strat1.execute()
strat2.execute()
Run Code Online (Sandbox Code Playgroud)
这将输出预期结果:
Strategy Example 0
Strategy Example 1 from execute 1
Strategy Example 2 from execute 2
Run Code Online (Sandbox Code Playgroud)
当然,在这种情况下,函数不能再单独使用,但仍然可以绑定到任何对象的任何其他实例,而没有任何接口限制.
Chr*_*eau 40
为搜索"蟒蛇战略模式"的Google员工回答了一个老问题,并在这里登陆......
在支持一流功能的语言中,这种模式几乎不存在.您可能需要考虑在Python中利用此功能:
def strategy_add(a, b):
return a + b
def strategy_minus(a, b):
return a - b
solver = strategy_add
print solver(1, 2)
solver = strategy_minus
print solver(2, 1)
Run Code Online (Sandbox Code Playgroud)
这种方法非常简洁.
此外,请务必查看Joe Gregorio的PyCon 2009关于Python和设计模式(或缺乏)的讨论:http://pyvideo.org/video/146/pycon-2009--thelack-of--design-模式功能于pyth
S.L*_*ott 32
你是对的,维基百科的例子没有帮助.它混淆了两件事.
战略.
Python的特性简化了Strategy的实现."没有必要明确地实现此模式"语句是不正确的.您经常需要实现策略,但Python通过允许您使用函数而不需要围绕函数的类包装器的开销来简化这一过程.
一,战略.
class AUsefulThing( object ):
def __init__( self, aStrategicAlternative ):
self.howToDoX = aStrategicAlternative
def doX( self, someArg ):
self. howToDoX.theAPImethod( someArg, self )
class StrategicAlternative( object ):
pass
class AlternativeOne( StrategicAlternative ):
def theAPIMethod( self, someArg, theUsefulThing ):
pass # an implementation
class AlternativeTwo( StrategicAlternative ):
def theAPImethod( self, someArg, theUsefulThing ):
pass # another implementation
Run Code Online (Sandbox Code Playgroud)
现在你可以做这样的事情了.
t = AUsefulThing( AlternativeOne() )
t.doX( arg )
Run Code Online (Sandbox Code Playgroud)
它将使用我们创建的策略对象.
第二,Python替代品.
class AUsefulThing( object ):
def __init__( self, aStrategyFunction ):
self.howToDoX = aStrategyFunction
def doX( self, someArg ):
self.howToDoX( someArg, self )
def strategyFunctionOne( someArg, theUsefulThing ):
pass # an implementation
def strategyFunctionTwo( someArg, theUsefulThing ):
pass # another implementation
Run Code Online (Sandbox Code Playgroud)
我们做得到.
t= AUsefulThing( strategyFunctionOne )
t.doX( anArg )
Run Code Online (Sandbox Code Playgroud)
这也将使用我们提供的策略功能.
为清楚起见,我仍然会使用伪接口:
class CommunicationStrategy(object):
def execute(self, a, b):
raise NotImplementedError('execute')
class ConcreteCommunicationStrategyDuck(CommunicationStrategy):
def execute(self, a, b):
print "Quack Quack"
class ConcreteCommunicationStrategyCow(CommunicationStrategy):
def execute(self, a, b):
print "Mooo"
class ConcreteCommunicationStrategyFrog(CommunicationStrategy):
def execute(self, a, b):
print "Ribbit! Ribbit!"
Run Code Online (Sandbox Code Playgroud)
我尝试用Python转换Head First设计模式第一章(涵盖策略模式)中的“Duck”示例:
class FlyWithRocket():
def __init__(self):
pass
def fly(self):
print 'FLying with rocket'
class FlyWithWings():
def __init__(self):
pass
def fly(self):
print 'FLying with wings'
class CantFly():
def __init__(self):
pass
def fly(self):
print 'I Cant fly'
class SuperDuck:
def __init__(self):
pass
def setFlyingBehaviour(self, fly_obj):
self.fly_obj = fly_obj
def perform_fly(self):
self.fly_obj.fly()
if __name__ == '__main__':
duck = SuperDuck()
fly_behaviour = FlyWithRocket()
#fly_behaviour = FlyWithWings()
duck.setFlyingBehaviour(fly_behaviour)
duck.perform_fly()
Run Code Online (Sandbox Code Playgroud)