Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何用Python编写与Wikipedia中的示例不同的策略模式?_Python_Design Patterns - Fatal编程技术网

如何用Python编写与Wikipedia中的示例不同的策略模式?

如何用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

在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 #=> 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一样简洁、优雅。但是你失去了信息;由于没有明确的接口,程序员被认为是成年人,知道他们在做什么
请注意,在Python中动态添加方法有3种方法:

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
作为参数传递

  • 仅绑定到实例(使用
    类型
    模块):

    strat0.execute=types.MethodType(executePlacement1,strat0)

    或者对于Python 2,还需要更改实例的类:

    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
    
  • 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 )
    

    这还将使用我们提供的一个策略功能。

    为搜索“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在视频中提到的关于“动态语言中的设计模式”的帖子。最好在构造函数中设置飞行行为,或者至少在构造函数中设置默认值。您可能会忘记设置它,否则会出错。这是一个模板模式,而不是策略