小编典典

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

python

在2009年Wikipedia中的Strategy
Pattern条目中,有一个用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代码中,“提交”按钮使用了另一种技术。我不知道Python代码是否也会像其他代码示例那样执行。

更新: 在Python中使用一流的函数可以缩短时间吗?


阅读 135

收藏
2020-12-20

共1个答案

小编典典

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一样干净简洁,优雅。但是你会丢失信息;由于没有显式接口,因此假定程序员是成年人,知道他们在做什么。

请注意,有3种方法可以在Python中动态添加方法:

  • 我给你看的方式 但是该方法将是静态的,不会传递“ self”参数。

  • 使用类名:

StrategyExample.execute = func

在这里,所有实例都将func作为execute方法,并self作为参数传递。

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

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

或使用Python 2,还需要更改实例的类:

strat0.execute = types.MethodType(executeReplacement1, strat0, StrategyExample)

与第一个示例一样,这会将新方法绑定到strat0和only 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

当然,在这些功能不能再单独使用的情况下,但是仍然可以绑定到任何对象的任何其他实例,而没有任何接口限制。

2020-12-20