管理多个类的类是"上帝对象"吗?

Dan*_*tti 13 language-agnostic oop god-object

阅读关于神对象的维基百科条目,它说当一个类知道太多或太多时,它就是一个神对象.

我看到了这背后的逻辑,但如果这是真的,那么你如何结合每一个不同的阶级呢?您是否总是使用主类来连接窗口管理,数据库连接等?

Odd*_*ing 16

主要功能/方法可以知道窗口,数据库和其他对象的存在.它可以执行总体任务,例如将模型引入控制器.

但这并不意味着它管理所有细节.它可能对数据库或窗口的实现方式一无所知.

如果确实如此,它可能会被指责为上帝的对象.

  • 那是对的.有时(并非总是)您需要一个主对象,但该对象应该只是实例化负责的类并委派责任.如果它试图自己做所有事情那么它就变成了上帝对象.组合和授权是使其不能成为一体的关键. (4认同)

WRe*_*ach 8

神对象是包含引用的对象,直接或间接地,以最如果不是在应用程序内的所有对象.正如问题所述,在应用程序中避免使用神对象几乎是不可能的. 某些对象必须包含对各种子系统的引用:UI,数据库,通信,业务逻辑等.请注意,上帝对象不需要是应用程序定义的.许多框架都内置了神对象,其名称如"应用程序上下文","应用程序环境","会话","激活器"等.

问题不在于是否存在神对象,而在于它是如何被使用的.我将以一个极端的例子说明......

假设在我的应用程序中,我想标准化显示数字时显示的精确小数位数.但是,我希望精度可以配置.我创建了一个类,其职责是将数字转换为字符串:

class NumberFormatter {
    ...
    String format(double value) {
        int decimalPlaces = getConfiguredPrecision();
        return formatDouble(value, decimalPlaces);
    }

    int getConfiguredPrecision() {
        return /* what ??? */;
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是,如何getConfiguredPrecision找出返回的内容?一种方法是提供NumberFormatter对它存储在名为的成员字段中的全局应用程序上下文的引用_appContext.然后我们可以写:

return _appContext.getPreferenceManager().getNumericPreferences().getDecimalPlaces();
Run Code Online (Sandbox Code Playgroud)

通过这样做,我们刚刚NumberFormatter成为一个神的对象!为什么?因为现在我们可以(间接地)通过其_appContext字段引用应用程序中的任何对象.这不好吗?是的.

我要写一个单元测试NumberFormatter.让我们设置参数......它需要一个应用程序上下文?!WTF,我需要模拟57种方法.哦,它只需要pref经理...... WTF,我必须模拟14种方法!数字首选!?!拧它,班级很简单,我不需要测试它...

假设应用程序上下文有另一种方法,getDatabaseManager().上周我们使用的是SQL,因此该方法返回了一个SQL数据库对象.但本周,我们决定更改为NoSQL数据库,该方法现在返回一个新类型.被NumberFormatter影响的变化?嗯,我记不清了...是的,它可能是,我看到它在构造函数中需要一个应用程序上下文...让我打开源代码并看一看......不,我们很幸运:它只访问getPreferenceManager()...现在让我们检查将应用程序上下文作为参数的其他93个类...

如果对首选项管理器或数字首选项对象进行了更改,则会出现相同的情况.这个故事的寓意是,一个对象应该仅仅包含对执行其工作所需的事物的引用,并且只包含那些事物.在这种情况下NumberFormatter,它需要知道的是一个整数 - 小数位数.它可以由知道幻数的应用程序上帝对象(或者pref管理器或更好的数字prefs)直接创建,而无需将格式化程序转换为上帝对象本身.此外,任何需要格式化数字的组件都可以被赋予格式化程序而不是上帝对象.四处奔走.

因此,总而言之,问题不在于上帝对象的存在,而在于无情地赋予其他对象神性状态的行为.

顺便提一下,正面解决这个问题的设计原理已经被称为德米特定律.或者"在餐馆付款时,给服务器你的钱而不是你的钱包."