工厂模式与常规构造函数的利弊

9 投票
5 回答
1961 浏览
提问于 2025-04-17 10:19

(我用的是Python 3.2,不过我觉得这个版本不太重要。)

我有一个叫 Data 的类,一个叫 Rules 的类,还有一个叫 Result 的类。我用小写字母来表示这些类的实例。

一个 rules 对象包含了一些规则,如果把这些规则应用到一个 data 对象上,就可以生成一个 result 对象。

我在考虑把那段(相对复杂且不断变化的)代码放在哪里,这段代码实际上是用来把规则应用到数据上的。我看到有两个选择:

  1. 把这段代码放在 Result 类的一个方法里,比如叫 parse_rulesResult 的构造函数会接收一个 rules 对象作为参数,然后把它传递给 self.parse_rules

  2. 把这段代码放在一个新的类 ResultFactory 里。ResultFactory 会是一个单例类,它有一个方法,比如叫 build_result,这个方法接收 rules 作为参数,并返回一个新建的 result 对象。

这两种方法各有什么优缺点呢?

5 个回答

1

你能把ResultFactory变成一个纯函数吗?如果你只需要一个函数,那创建一个单例对象就没什么用处了。

2

第三种情况:

你可能想考虑第三种情况:

  • 把代码放在方法 Rules.__call__ 里面。
    像这样实例化 Resultresult = rules(data)

优点:

  • Result 对生成它的 Rules 完全不需要了解(甚至可能对原始的 Data 也不需要了解)。
  • 每个 Rules 的子类可以自定义它的 Result 创建方式。
  • 这感觉很自然(对我来说):把 Rules 应用到 Data 上会得到 Result
  • 而且你会有几个 GRASP 原则在支持你:
    • 创建者Rules 的实例拥有创建 Result 实例所需的初始化信息,并在创建时传递这些信息。
    • 信息专家:信息专家原则会让你把责任放在最有信息的类上,以便完成这个任务。

副作用:

  • 耦合:你会增加 RulesData 之间的耦合度:
    • 你需要把整个数据集传递给每个 Rules
    • 这意味着每个 Rules 应该能够决定它将应用于哪些数据。
3

GRASP设计原则是一些指导方针,帮助我们在面向对象设计中给类和对象分配责任。比如,创建者模式的建议是:一般来说,如果以下一种或多种情况成立,类B应该负责创建类A的实例:

  • 类B的实例包含或组合了类A的实例
  • 类B的实例记录了类A的实例
  • 类B的实例与类A的实例有紧密的使用关系
  • 类B的实例拥有类A实例所需的初始化信息,并在创建时传递这些信息。

在你的例子中,你有一些复杂且不断变化的代码来对数据应用规则。这表明可以使用工厂模式

把代码放在结果中是不合适的,因为1) 结果并不创建结果,2) 结果也不是信息专家(也就是说,它们没有大部分所需的知识)。

简而言之,结果工厂似乎是一个合理的地方,可以集中处理如何将规则应用到数据上以生成结果。如果你试图把所有这些逻辑都放进结果或规则的类构造函数中,会导致紧密耦合和缺乏内聚性。

撰写回答