python - 这是工厂模式的正确实现吗?

标签 python design-patterns

首先,这不是作业。其次,它有点长。抱歉并提前感谢您的耐心等待。

有一个.. 游戏,基本上它为您提供了一个开始条件、一个期望的结果、一组进程和最大进程数。工作是找到执行过程的正确顺序,以便获得所需的结果。
所以我觉得用电脑来解决问题可能会好些。最大步长通常在 10 以下,因此使用蛮力应该是安全的。

这是我的解决方案代码(顺便说一句,它是在 python 中)。简单来说,我为每个进程创建一个对象,然后把它们放到一个列表中。在我遍历列表的每一步中,将参数(起始条件、预期结果等)传递给流程对象,并检查输出是否与预期结果匹配。如果匹配,则返回被调用进程的堆栈。

class Puzzle:
    def __init__(self, initial_num, num_steps, result, list_process):
        self.initial_num = initial_num
        self.num_steps = num_steps
        self.result = result
        self.list_process = list_proces

    def solve(self):
        for process in self.list_process:
            stack = process.run(self.initial_num, self.num_steps, self.result, self.list_process)
            if stack is not None:
                return stack
        return None

对于流程,因为有许多类型的流程,并且在每种情况下都有不同的流程组合要执行。我碰巧使用了一点 Java,所以我使用了多态性的想法,这在 Python 中并不真正需要,但我认为它是一个简洁的结构。

class ProcessBase:

    @property
    def name(self):
        print("need to rewrite")

    def do_process(self, num_input):
        print("need to rewrite")

    def run(self, input_, steps_remain, result, processes_next):
        if steps_remain is 0:
            return None
        try:
            output= self.do_process(input_)
        except RuntimeError:
            return None
        if output == result:
            stack = [self.name]
            return stack
        for process in processes_next:
            stack = process.run(output, steps_remain - 1, result, processes_next)
            if stack is not None:
                stack.append(self.name)
                return stack
        return None

class ProcessA(ProcessBase):

    def __init__(self, param):
        super().__init__()
        self.param = param

    @property
    def name(self):
        return "ProcessA" + self.param

    def do_process(self, input):
        # do the process(e.g. add 1 to the input)
        output = input + 1
        return output

所以基本上每个进程中的run() 都是一样的,所以我只需要重写name() 来显示调用堆栈,以及do_process() 来重写实际进程。然后我的工厂方法(它不是一个类,因为我认为不需要多个工厂)如下所示。

def process_factory(str_input):
    if str_input=="A":
        return ProcessA()
    elif str_input=="B":
        return ProcessB()
    # etc

所以在实际使用中,我可以保留大部分代码不变。当有新的进程类型时,我只需要添加一个新类,覆盖name()和do_process(),在process_factory()方法中添加几行就可以了。但是我对此仍然没有信心。 我的问题(最后!)是:

  1. 这个实现在 Python 中是否正确,甚至过度?
  2. 在 process_factory() 方法中,“if...elif...”变得很长,我想把它做成字典。如下所示:

    methods = {'A': ProcessA(), 'B': ProcessB() }

    但这意味着即使不使用,也会创建所有对象。我也可以将 dict 中的构造函数替换为返回对象的方法,但是当我需要添加另一种类型的 Process 时,我需要编写更多行。有没有更好的办法?

  3. 一段时间后,出现了一种新的进程类型,它不会改变输入,但会改变进程之后的行为方式。
    例如,ProcessA 是输入加 1,ProcessB 是减 1。但是在 ProcessC 之后,ProcessA 变成加 2,ProcessB 变成减 2。我不能直接修改 ProcessA,因为原始副本需要在下一个循环。 我的解决方案是:

    • 添加一个新的 ProcessC 类并重写 run() 方法。它对原始代码的改动最小,但有点违背了原始结构的想法。

    • 改变整个逻辑,使一个过程不仅影响输入,而且影响其他参数(例如可用的过程,甚至结果)。但是会有很大的变化,我需要考虑如何在创建新的更改版本的流程的同时维护旧的流程副本。

    您认为最好的解决方案应该是什么?

最佳答案

正如您所说,字典是比多个 if 更好的解决方案。您可以通过 classes 本身的值来避免实例化每个对象,它们是 Python 中的一流对象;然后你可以实例化字典查找的结果:

methods = {'A': [ProcessA, [param1, param2]], 'B', [ProcessB, [param3, param4], ...}
klass, params = methods[str_input]
return klass(*params)

关于python - 这是工厂模式的正确实现吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58501354/

相关文章:

PHP:管理实体类型的设计模式

javascript - 毫无疑问地询问用户详细信息

python - 如何在python3中键入提示matplotlib.axes._subplots.AxesSubplots对象

python:一个有很多方法的类需要更长的时间来初始化吗?

python - 如何在单元测试中使用 assert_frame_equal

javascript - 您网站上的自定义 jQuery 脚本有多少行代码?多少才算是太多呢?

python - 如何获取列表值的索引以及用户输入要选择的值

python - Django 获取其派生类具有 mixin 的所有基类对象

c++ - 如何让人们相信一个有 11975 行代码的类是不好的? (不是吗?)

java - 对于不返回任何内容的类使用 java.lang.Void 是否方便?