如何用Python编写与Wikipedia中的示例不同的策略模式?
在2009年维基百科关于战略模式的条目中,有一个例子 大多数其他代码示例执行以下操作:如何用Python编写与Wikipedia中的示例不同的策略模式?,python,design-patterns,Python,Design Patterns,在2009年维基百科关于战略模式的条目中,有一个例子 大多数其他代码示例执行以下操作: 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 #=> D
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代码中,提交按钮使用了不同的技术。我想知道,如果Python代码也像其他代码示例那样运行,它会是什么样子
更新:在Python中使用一流函数是否可以缩短时间?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()
输出:
原始执行
战略1
战略2
主要区别在于:
- 您不需要编写任何其他类或实现任何接口
- 相反,您可以传递将绑定到所需方法的函数引用
- 这些函数仍然可以单独使用,如果需要,原始对象可以具有默认行为(可以使用
模式)if func==None
- 事实上,它与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)
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()
- 我向你展示的方式。但是该方法是静态的,它不会传递“self”参数
- 使用类名:
StrategyExample.execute=func
func
作为execute
方法,并将获得self
作为参数传递
- 仅绑定到实例(使用
模块):类型
或者对于Python 2,还需要更改实例的类:strat0.execute=types.MethodType(executePlacement1,strat0)
strat0.execute=types.MethodType(executePlacement1,strat0, 策略示例)
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()
您将获得:
回溯(最近一次呼叫最后一次):
文件“test.py”,第28行,在
strat1.execute()
文件“test.py”,第13行,在ExecutePlacement1中
打印self.name+“从执行1”
NameError:未定义全局名称“self”
因此,正确的代码应该是:
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()
这将输出预期结果:
策略示例0
执行1中的策略示例1
执行2中的策略示例2
当然,如果函数不能单独使用,但仍然可以绑定到任何对象的任何其他实例,而不受任何接口限制。为了清楚起见,我仍然会使用伪接口:
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!"
你说得对,维基百科的例子没有帮助。它把两件事混为一谈
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
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 )
这还将使用我们提供的一个策略功能。为搜索“python策略模式”并登陆此处的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)
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()
这种方法非常简洁
另外,请务必查看Joe Gregorio的PyCon 2009关于Python和设计模式(或其缺乏)的讨论:我试图转换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)
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()
你用哪一种?你推荐用什么?@Arrieta:两者都用。两者都推荐。它们有不同的应用。如果策略有多个方法,或者(某种程度上)是有状态的,那么您需要第一个方法。在更典型的情况下,第二种方法很有效。如果你和很多java或C++程序员一起工作,你必须先使用它,因为第二个程序会混淆它们。那么为什么我们在Python中有类呢?有时候,设计模式在大型项目中很有用,但你无法摆脱它:)工作。在另一个视频中被删除。@vivek One没有专门用于促进设计模式的python或任何其他语言类。许多事物都可以用类来很好地表示。但是,要求类表示命令或策略模式是一个弱点。任何具有适当闭包的语言都可以不使用闭包。而大型项目并不是课程的具体要求。许多语言根本没有类,但却用于创建大型项目。当然,类是Python中表示数据类型的唯一方法,因此您无法摆脱它们。是Peter Norvig在视频中提到的关于“动态语言中的设计模式”的帖子。最好在构造函数中设置飞行行为,或者至少在构造函数中设置默认值。您可能会忘记设置它,否则会出错。这是一个模板模式,而不是策略