如何通过方法的运行时选择来实现策略模式?

Hug*_*lle 1 python inheritance strategy-pattern

语境

我正在尝试在 Python 2.7 中实现策略模式的一些变体。我希望能够实例化“my_strategy”基类,但在运行时在“score”方法的不同实现之间切换。我将在“my_strategy”中有许多常用方法,但有一堆“score”实现。主要说明了我想如何使用它。当然,这里的评分实现是虚拟的。

我尝试过的(即到目前为止我的代码)

策略.py:

from algo_one import *
#from algo_two import *


class my_strategy ( object ):

    def __init__(self, candidate = ""):
        self.candidate = candidate
        self.method = 'default'
        self.no = 10
        self._algo = algo_one

    def set_strategy(self, strategy='default'):
        self.strategy = strategy
        if self.strategy == 'algo_one':
            self._algo = algo_one
        elif self.strategy == 'algo_two':
            # self._algo = algo_two
            pass 
        else:
            self._algo = None

    def score(self, *args):
        if len(args) > 0:
            self.candidate = args[0]
        self._algo.score(self.candidate)

if  __name__ == "__main__":
    s = my_strategy()  
    s.strategy = 'algo_one'
    s.candidate = "hello world"
    print s.score()  
    print s.score("hi")
    # s.set_method('algo_two')
    # print s.score("hi")
Run Code Online (Sandbox Code Playgroud)

我想将选定的策略保存在某种指向子类方法的私有指针中。

algo_one.py:

from strategy import my_strategy
class algo_one ( my_strategy ):    
    def score(self, candidate):
        return len(candidate)*self.no 
Run Code Online (Sandbox Code Playgroud)

我可以有一个无类方法,但稍后我需要访问基类的公共变量。

算法_two.py:

from strategy import my_strategy
class algo_two ( my_strategy ):
    def score(self, candidate):
        return len(candidate)*3 
Run Code Online (Sandbox Code Playgroud)

我也有一个空的init .py 。

错误

1. 在分数 self._algo.score(self.candidate)

类型错误:必须使用 algo_one 实例作为第一个参数调用未绑定方法 Score()(改为使用 str 实例)

2. 如果我取消注释第二个策略的导入:

from algo_two import *
Run Code Online (Sandbox Code Playgroud)

我收到以下错误。

导入错误:无法导入名称 my_strategy

我的猜测是我遇到了某种循环依赖。

3.

from algo_one import *
Run Code Online (Sandbox Code Playgroud)

这显然不太漂亮(无法检测未定义的名称),但如果我

from algo_one import algo_one
Run Code Online (Sandbox Code Playgroud)

我明白了

导入错误:无法导入名称 algo_one

问题

我认为这些错误是交织在一起的,而且我的方法作为一个整体可能存在缺陷。如果不仅仅是解决错误,我还会寻找改进设计的建议。或者任何评论,真的。我也愿意接受有关这个问题标题的建议。谢谢你!

bru*_*ers 5

你让它变得比需要的更加复杂。Python 函数是第一类对象,因此在 Python 中实现策略模式的最简单方法是将“策略”函数传递给“上下文”对象(使用该策略的对象)。最好的部分是任何可调用对象(即:任何实现该__call__方法的对象)都可以工作。

def default_score_strategy(scorer):
    return len(scorer.candidate) * 3

def universal_answer_score_strategy(scorer):
    return 42 # definitly the universal answer <g>

class ComplicatedStrategy(object):
    def __init__(self, factor):
        self.factor = factor

    def __call__(self, scorer):
         return len(scorer.candidate) * self.factor


class Scorer(object):
    def __init__(self, candidate="", strategy=default_score_strategy):
        self.candidate = candidate
        self.strategy = strategy

    def score(self):
        return self.strategy(self)

s1 = Scorer("foo")
s2 = Scorer("bar", strategy=universal_answer_score_strategy)
s3 = Scorer("baaz", strategy=ComplicatedStrategy(365))
Run Code Online (Sandbox Code Playgroud)

请注意,您的策略不必与类位于同一模块中Scorer(当然,默认的除外),并且包含该类的模块Scorer不必导入策略模块 - 也不知道策略在哪里定义为:

# main.py

from mylib.scores import Scorer
from myapp.strategies import my_custom_strategy

s = Scorer("yadda", my_custom_strategy)
Run Code Online (Sandbox Code Playgroud)