13

Reading the wikipedia entry about God Objects, it says that a class is a god object when it knows too much or does too much.

I see the logic behind this, but if it's true, then how do you couple every different class? Don't you always use a master class for connecting window management, DB connections, etc?

Daniel Sorichetti
  • 1,921
  • 1
  • 20
  • 34

4 Answers4

16

The main function/method may know about the existence of the windows, databases, and other objects. It may perform over-arching tasks like introduce the model to the controller.

But that doesn't mean it manages all the little details. It probably doesn't know anything about how the database or windows are implemented.

If it did, it could be accused of being a God object.

FooBar
  • 1,663
  • 2
  • 12
  • 19
Oddthinking
  • 24,359
  • 19
  • 83
  • 121
  • 4
    That is right. Sometimes (not always) you need a master object but that object should just instantiate responsible classes and delegate the responsibility. If it tries to do everything on its own then it becomes god-object. Composition and Delegation is the key which can keep it from becoming one. – Unmesh Kondolikar Dec 30 '10 at 06:00
8

A god object is an object that contains references, directly or indirectly, to most if not all objects within an application. As the question observes, it is almost impossible to avoid having a god object in an application. Some object must hold references to the various subsystems: UI, database, communications, business logic, etc. Note that the god object need not be application-defined. Many frameworks have built-in god objects with names like "application context", "application environment", "session", "activator", etc.

The issue is not whether a god object exists, but rather how it is used. I will illustrate with an extreme example...

Let's say that in my application I want to standardize how many decimal places of precision to show when displaying numbers. However, I want the precision to be configurable. I create a class whose responsibility is to convert numbers to strings:

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

    int getConfiguredPrecision() {
        return /* what ??? */;
    }
}

The question is, how does getConfiguredPrecision figure out what to return? One way would be to give NumberFormatter a reference to the global application context which it stores in a member field called _appContext. Then we could write:

return _appContext.getPreferenceManager().getNumericPreferences().getDecimalPlaces();

By doing this, we have just made NumberFormatter into a god object as well! Why? Because now we can (indirectly) reference virtually any object in the application through its _appContext field. Is this bad? Yes, it is.

I'm going to write a unit test for NumberFormatter. Let's set up the parameters... it needs an application context?! WTF, that has 57 methods I need to mock. Oh, it only needs the pref manager... WTF, I have to mock 14 methods! Numeric prefs!?! Screw it, the class is simple enough, I don't need to test it...

Let's say that the application context had another method, getDatabaseManager(). Last week we were using SQL, so the method returned an SQL database object. But this week, we've decided to change to a NoSQL database and the method now returns a new type. Is NumberFormatter affected by the change? Hmmm, I can't remember... yeah, it might be, I see it takes an application context in the constructor... let me open the source and take a look... nope, we're in luck: it only accesses getPreferenceManager()... now let's check the other 93 classes that take an application context as a parameter...

This same scenario occurs if a change is made to the preferences manager, or the numeric preferences object. The moral of the story is that an object should only hold references to the things that it needs to perform its job, and only those things. In the case of NumberFormatter, all it needs to know is a single integer -- the number of decimal places. It could be created directly by the application god object who knows the magic number (or the pref manager or better still, numeric prefs), without turning the formatter into a god object itself. Furthermore, any components that need to format numbers could be given a formatter instead of the god object. Wins all around.

So, to summarize, the problem is not the existence of a god object but rather the act of conferring god-like status to other objects willy-nilly.

Incidentally, the design principle that tackles this problem head-on has become known as the Law of Demeter. Or "when paying at a restaurant, give the server your money not your wallet."

WReach
  • 18,098
  • 3
  • 49
  • 93
  • I tried to resist writing this, but failed -- introducing the Cylon Programming Principle: "In well-designed software, there is only one god". – WReach Jan 23 '11 at 16:38
  • I appreciate your answer. Interesting read, i'll research further :) thanks! – Daniel Sorichetti Jan 24 '11 at 04:18
  • 1
    Do not be deceived, the God object cannot be mocked. – Kevin S Nov 09 '13 at 01:15
  • This is an old answer and a good one. But, I am missing the actual solution. How does one give a formatter, instead of the god object? Or rather, how does one avoid "conferring god-like status to other objects willy-nilly"? – m8a Dec 16 '16 at 05:58
  • @Skooppa.com Let's say we have a component that formats labels that might include numbers. If we say `new LabelMaker(appContext)`, then that component has the power to do anything that `appContext` can do. If instead we say `new LabelMaker(numberFormatter)` then it only has the power to format numbers. In the former case, `LabelMaker` is exaggerating about its dependencies (e.g. why on Earth would `LabelMaker` need access to `appContext.haltSystem()`?). In the latter case, the actual dependency is explicit and thus easier to reason about without reading the source of `LabelMaker`. – WReach Dec 16 '16 at 16:32
  • Thanks @WReach. I looked into this more. I found some pretty cool videos on this. The best one is with the analogy, "When you want a banana, why should you get the gorilla with it?" https://www.youtube.com/watch?v=wfMtDGfHWpA My curiosity stems from this "framework". It is basically becomes a very large object, depending on the application, from what I understand of it. https://github.com/xpepermint/contextablejs – m8a Dec 17 '16 at 12:06
  • 1
    "give the server your money not your wallet." What does that say about credit card payment? – Damian Yerrick Oct 07 '18 at 15:18
3

In my experience this most often occurs when you're dealing with code that is the product of "Develop as you go" project management (or lack there of). When a project is not thought through and planned and object responsibilities are loose and not delegated properly. In theses scenarios you find a "god-object" being the catchall for code that doesn't have any obvious organization or delegation.

It is not the interconnectedness or coupling of the different classes that is the problem with god-objects, it's the fact that a god-object many times can accomplish most if not all responsibilities of it's derived children, and are fairly unpredictable (by anyone other than the developer) as to what their defined responsibilities are.

jondavidjohn
  • 61,812
  • 21
  • 118
  • 158
2

Simply knowing about "multiple" classes doesn't make one a God; knowing about multiple classes in order to solve a problem that should be split into several sub-problems does make one a God.

I think the focus should be on whether a problem should be split into several sub-problems, not on the number of classes a given object knows about (as you pointed out, sometimes knowing about several classes is necessary).

Gods are over-hyped.

ClosureCowboy
  • 20,825
  • 13
  • 57
  • 71