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

问题描述 投票:1回答:2

首先,这不是家庭作业。其次,它有点长。抱歉,谢谢您的耐心配合。

有一个..游戏,基本上它为您提供了开始条件,所需结果,一堆过程和最大过程数。工作是找到正确的执行过程顺序,以便获得所需的结果。因此,我认为使用计算机解决该问题可能会很好。最大步长通常小于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
        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 ...”变得相当长,我当时正在考虑将其作为字典。如下所示:

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

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

  3. 过一会儿,有一种新型的流程,它不会更改输入,但会更改其后的行为方式,这与我当前的设计并不真正兼容。我的解决方案是:

    • 添加新的Process类并重写run()方法。它对原始代码所做的更改最少,但是有点违背原始结构的想法。
    • 更改整个逻辑,这样一个过程不仅会影响输入,还会影响其他参数(例如可用过程,甚至结果)。但是会有很多更改,我需要考虑如何在创建新的变更版本的过程中维护流程的旧副本。

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

python design-patterns
2个回答
2
投票

正如您所说,与多个ifs相比,字典是更好的解决方案。您可以通过使用classses本身的值来避免实例化每个对象,这些值是Python中的一流对象。然后可以实例化dict查询的结果:

methods = {'A': ProcessA, 'B', ProcessB, ...}
return methods[str_input]()

0
投票

((1)您的实现对我来说似乎不错,但我不是专家。

对于名称类属性,您可以改用__str____repr__方法。


class ProcessBase:

   def __repr__(self):
       return f"{self.__class__.__name___} params : {self.param}"

   def __str__(self):
       return self.__repr__

以这种方式,bo每次都需要重新输入名称。

((2)如前所述,我还将使用字典。

def process_factory(str_input):
    methods = {'A': ProcessA, 'B', ProcessB, ...}  
    return methods[str_input]()

您在难题中的求解方法成为。

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

((3)

© www.soinside.com 2019 - 2024. All rights reserved.