9

(使用 Python 3.2,尽管我怀疑它是否重要。)

我有class Data,class Rules和 类Result。我使用小写字母来表示类的一个实例。

对象包含规则,如果rules应用于data对象,则可以创建result对象。

我正在决定将实际将规则应用于数据的(相当复杂和不断发展的)代码放在哪里。我可以看到两个选择:

  1. 将该代码放在类Result方法中,例如parse_rules. Result构造函数会将对象作为参数rules,并将其传递给self.parse_rules.

  2. 将该代码放入一个新类ResultFactory中。ResultFactory将是一个单例类,它有一个方法,say build_result,它rules作为参数并返回一个新建的result对象。

这两种方法的优缺点是什么?

4

5 回答 5

3

GRASP 设计原则为在面向对象设计中为类和对象分配责任提供了指导。例如,Creator模式建议: 通常,如果以下一个或多个适用于以下情况,则类 B 应该负责创建类 A 的实例:

  • B 的实例包含或组合聚合了 A 的实例
  • B 的实例记录 A 的实例
  • B 的实例密切使用 A 的实例
  • B 的实例具有 A 实例的初始化信息并在创建时传递它。

在您的示例中,您有用于将规则应用于数据的复杂且不断发展的代码。这表明使用工厂模式

将代码放入结果中是禁忌的,因为 1) 结果不会产生结果,以及 2) 结果不是信息专家(即他们没有所需的大部分知识)。

简而言之,ResultFactory似乎是一个合理的地方,可以集中有关如何将规则应用于数据以生成结果的知识。如果您尝试将所有这些逻辑推送到结果或规则的类构造函数中,则会导致紧密耦合和内聚损失。

于 2012-01-16T01:59:54.713 回答
2

第三种情况:

您可能需要考虑第三种情况:

  • 将代码放入方法Rules.__call__中。
    像这样实例化Resultresult = rules(data)

优点:

  • Results 可能完全不知道Rules生成它们的 (甚至可能是原始的Data)。
  • 每个Rules子类都可以自定义其Result创建。
  • 感觉很自然(对我来说):Rules应用于Datayield Result
  • 您将掌握一些 GRASP 原则:
    • Creator:实例Rules具有实例的初始化信息Result并在创建时传递它。
    • 信息专家:信息专家将导致将责任放在具有履行职责所需的最多信息的班级上。

副作用:

  • 耦合:您将提高和之间的Rules耦合Data
    • 您需要将整个数据集传递给每个Rules
    • 这意味着每个人都Rules应该能够决定将应用哪些数据。
于 2012-01-16T09:42:17.010 回答
1

为什么不把规则放在自己的班级里呢?如果您创建一个 RuleBase 类,则每个规则都可以从它派生。这样,当数据需要应用规则时,可以使用多态性。数据不需要知道或关心应用了哪些规则实例(除非数据本身知道应该应用哪些规则)。

当需要调用规则时,数据实例可以全部使用 RuleBase.ExecuteRules() 并将自身作为参数传入。如果 Data 知道需要哪个 Rule,则可以直接从 Data 中选择正确的 Rule 子类。或者可以使用其他一些设计模式,例如责任链,其中 Data 调用该模式并让 Result 返回。

这将是一个很棒的白板讨论。

于 2012-01-16T02:09:02.357 回答
1

你能让 ResultFactory 成为一个纯函数吗?如果你只需要一个函数,那么创建一个单例对象是没有用的。

于 2012-01-16T07:49:35.643 回答
0

好吧,第二个是彻头彻尾的愚蠢,尤其是在单身的情况下。如果Result需要Rules创建一个实例,而没有它就无法创建一个实例,它应该将其作为__init__. 无需购买图案。

于 2012-01-16T02:00:01.913 回答