工厂模式与常规构造函数的利弊
(我用的是Python 3.2,不过我觉得这个版本不太重要。)
我有一个叫 Data
的类,一个叫 Rules
的类,还有一个叫 Result
的类。我用小写字母来表示这些类的实例。
一个 rules
对象包含了一些规则,如果把这些规则应用到一个 data
对象上,就可以生成一个 result
对象。
我在考虑把那段(相对复杂且不断变化的)代码放在哪里,这段代码实际上是用来把规则应用到数据上的。我看到有两个选择:
把这段代码放在
Result
类的一个方法里,比如叫parse_rules
。Result
的构造函数会接收一个rules
对象作为参数,然后把它传递给self.parse_rules
。把这段代码放在一个新的类
ResultFactory
里。ResultFactory
会是一个单例类,它有一个方法,比如叫build_result
,这个方法接收rules
作为参数,并返回一个新建的result
对象。
这两种方法各有什么优缺点呢?
5 个回答
你能把ResultFactory变成一个纯函数吗?如果你只需要一个函数,那创建一个单例对象就没什么用处了。
第三种情况:
你可能想考虑第三种情况:
- 把代码放在方法
Rules.__call__
里面。
像这样实例化Result
:result = rules(data)
优点:
Result
对生成它的Rules
完全不需要了解(甚至可能对原始的Data
也不需要了解)。- 每个
Rules
的子类可以自定义它的Result
创建方式。 - 这感觉很自然(对我来说):把
Rules
应用到Data
上会得到Result
。 - 而且你会有几个 GRASP 原则在支持你:
- 创建者:
Rules
的实例拥有创建Result
实例所需的初始化信息,并在创建时传递这些信息。 - 信息专家:信息专家原则会让你把责任放在最有信息的类上,以便完成这个任务。
- 创建者:
副作用:
- 耦合:你会增加
Rules
和Data
之间的耦合度:- 你需要把整个数据集传递给每个
Rules
- 这意味着每个
Rules
应该能够决定它将应用于哪些数据。
- 你需要把整个数据集传递给每个
GRASP设计原则是一些指导方针,帮助我们在面向对象设计中给类和对象分配责任。比如,创建者模式的建议是:一般来说,如果以下一种或多种情况成立,类B应该负责创建类A的实例:
- 类B的实例包含或组合了类A的实例
- 类B的实例记录了类A的实例
- 类B的实例与类A的实例有紧密的使用关系
- 类B的实例拥有类A实例所需的初始化信息,并在创建时传递这些信息。
在你的例子中,你有一些复杂且不断变化的代码来对数据应用规则。这表明可以使用工厂模式。
把代码放在结果中是不合适的,因为1) 结果并不创建结果,2) 结果也不是信息专家(也就是说,它们没有大部分所需的知识)。
简而言之,结果工厂似乎是一个合理的地方,可以集中处理如何将规则应用到数据上以生成结果。如果你试图把所有这些逻辑都放进结果或规则的类构造函数中,会导致紧密耦合和缺乏内聚性。