在2009年维基百科的战略模式条目中,有一个例子written in 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
在Python代码中,一个不同的技术与Submit按钮一起使用。我想知道如果Python代码也按照其他代码示例的方式执行它会是什么样子。
更新:使用Python中的第一类函数可以缩短它吗?
答案 0 :(得分:65)
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()
输出:
Original execution
Strategy 1
Strategy 2
主要区别是:
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()
你会得到:
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
所以正确的代码是:
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()
这将输出预期结果:
Strategy Example 0
Strategy Example 1 from execute 1
Strategy Example 2 from execute 2
当然,如果函数不能再单独使用,但仍然可以绑定到任何对象的任何其他实例,没有任何接口限制。
答案 1 :(得分:39)
为那些搜索过“蟒蛇战略模式”的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)
这种方法非常简洁。
另外,请务必查看Joe Gregorio的PyCon 2009关于Python和设计模式(或缺乏)的讨论:http://pyvideo.org/video/146/pycon-2009--the--lack-of--design-patterns-in-pyth
答案 2 :(得分:31)
你是对的,维基百科的例子没有帮助。它混淆了两件事。
<强>策略强>
简化策略实施的Python功能。 “没有必要明确地实现此模式”语句是不正确的。您经常需要实现策略,但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
现在你可以做这样的事情。
t = AUsefulThing( AlternativeOne() )
t.doX( arg )
它将使用我们创建的策略对象。
其次,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
我们可以做到这一点。
t= AUsefulThing( strategyFunctionOne )
t.doX( anArg )
这也将使用我们提供的策略功能。
答案 3 :(得分:9)
为清楚起见,我仍然会使用伪接口:
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!"
答案 4 :(得分:1)
我试图改变鸭子&#39; Python中Head First Design Pattern的第1章(涵盖战略模式)的例子:
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()