【发布时间】:2011-06-01 09:45:15
【问题描述】:
阅读the wikipedia entry about God Objects,它说当一个类知道太多或做得太多时,它就是一个上帝对象。
我看到了这背后的逻辑,但如果这是真的,那么你如何耦合每个不同的类?你不是一直用master类来连接窗口管理、DB连接等吗?
【问题讨论】:
标签: oop language-agnostic god-object
阅读the wikipedia entry about God Objects,它说当一个类知道太多或做得太多时,它就是一个上帝对象。
我看到了这背后的逻辑,但如果这是真的,那么你如何耦合每个不同的类?你不是一直用master类来连接窗口管理、DB连接等吗?
【问题讨论】:
标签: oop language-agnostic god-object
主函数/方法可能知道窗口、数据库和其他对象的存在。它可以执行总体任务,例如将模型引入控制器。
但这并不意味着它可以管理所有的小细节。它可能对数据库或窗口是如何实现的一无所知。
如果是这样,它可能会被指责为上帝的对象。
【讨论】:
上帝对象 是一个对象,它直接或间接地包含对应用程序中大多数(如果不是全部)对象的引用。正如问题所观察到的,在应用程序中避免使用上帝对象几乎是不可能的。 一些 对象必须包含对各种子系统的引用:UI、数据库、通信、业务逻辑等。请注意,上帝对象不必是应用程序定义的。许多框架都有内置的上帝对象,名称如“应用程序上下文”、“应用程序环境”、“会话”、“激活器”等。
问题不在于神物是否存在,而在于它是如何被使用的。我会用一个极端的例子来说明......
假设在我的应用程序中,我想标准化显示数字时要显示多少个小数位精度。但是,我希望精度是可配置的。我创建了一个类,其职责是将数字转换为字符串:
class NumberFormatter {
...
String format(double value) {
int decimalPlaces = getConfiguredPrecision();
return formatDouble(value, decimalPlaces);
}
int getConfiguredPrecision() {
return /* what ??? */;
}
}
问题是,getConfiguredPrecision 如何确定返回什么?一种方法是给NumberFormatter 一个对全局应用程序上下文的引用,它存储在一个名为_appContext 的成员字段中。然后我们可以写:
return _appContext.getPreferenceManager().getNumericPreferences().getDecimalPlaces();
通过这样做,我们刚刚将NumberFormatter 也变成了一个上帝对象!为什么?因为现在我们可以(间接地)通过其_appContext 字段引用应用程序中的几乎任何对象。这很糟糕吗?是的。
我将为NumberFormatter 编写一个单元测试。让我们设置参数...它需要一个应用程序上下文?! WTF,我需要模拟 57 种方法。哦,它只需要pref manager... WTF,我必须模拟14种方法!数字首选项!?!算了,类够简单的,不用我去测试了……
假设应用程序上下文有另一个方法getDatabaseManager()。上周我们使用的是 SQL,因此该方法返回了一个 SQL 数据库对象。但本周,我们决定更改为 NoSQL 数据库,该方法现在返回一个新类型。 NumberFormatter 是否受到更改的影响?嗯,我不记得了……是的,可能是,我看到它在构造函数中需要一个应用程序上下文……让我打开源代码看看……不,我们很幸运:它只访问getPreferenceManager()...现在让我们检查其他93个将应用程序上下文作为参数的类...
如果对首选项管理器或数字首选项对象进行更改,则会出现相同的情况。这个故事的寓意是一个对象应该只包含对它执行其工作所需的事物的引用,并且只有那些事物。对于NumberFormatter,它只需要知道一个整数——小数位数。它可以由知道幻数的应用程序上帝对象(或首选项管理器或更好的数字首选项)直接创建,而无需将格式化程序本身变成上帝对象。此外,任何需要格式化数字的组件都可以使用格式化程序而不是上帝对象。胜在四方。
所以,总而言之,问题不在于上帝对象的存在,而是不择手段地赋予其他对象类似上帝的地位的行为。
顺便说一句,正面解决这个问题的设计原则被称为Law of Demeter。或者“在餐厅付款时,给服务员你的钱而不是你的钱包。”
【讨论】:
仅仅了解“多个”课程并不能使一个人成为上帝;了解多个类为了解决一个应该分成几个子问题的问题 确实使一个人成为上帝。
我认为重点应该放在一个问题是否应该分成几个子问题,而不是给定对象知道的类的数量(正如你所指出的,有时知道几个课程是必要的)。
众神被夸大了。
【讨论】:
根据我的经验,这种情况最常发生在您处理的代码是“随用随开发”项目管理的产品(或缺少该产品)时。当一个项目没有经过深思熟虑和计划并且对象职责松散并且没有正确委派时。在这些场景中,您会发现“上帝对象”是没有任何明显组织或委托的代码的统称。
神对象的问题不是不同类的互连或耦合,而是神对象多次可以完成其派生子对象的大部分(如果不是全部)职责,并且是相当不可预测的(由开发人员以外的任何人)了解他们定义的职责是什么。
【讨论】: