The God object problem
I’ve seen it in just about every application, but I’ve only now found the right term for it — God object.
a God object is an object that knows too much or does too much
I mean an object that plays a central role throughout the application, a bit like the central brain of humanity from the TV series Návštěvníci. The trouble is that it keeps growing. Eventually you end up with an interface with twenty or more methods, which hardly makes the API any easier to understand, to say nothing of the implementation.
I think it’s perfectly fine for an application to have a business facade that brings several operations together. What’s often wrong is how the facade is designed and, above all, how it’s implemented. Let’s look at a practical example.
public interface ObjednavkovaSluzba {
public void vytvorObjednavku(Objednavka objednavka);
public void smazObjednavku(Objednavka objednavka);
public void aktualizujObjednavku(Objednavka objednavka);
public Objednavka nactiObjednavku(Serializable identifikator);
public void zpracujObjednavku(Serializable identifikator);
public void zrusObjednavku(Serializable identifikator);
}
As the interface shows, we’ve mixed two responsibilities (there are usually more than two). We have the CRUD (Create, Read, Update, Delete) operations for creating an order and the operations for processing it. It makes sense to split the interface. How can we do that while still offering a single, central interface for working with orders?
It’s quite simple. We split it into two interfaces along the lines of those responsibilities and keep the ObjednavkovaSluzba interface. We do that by composing it from those two interfaces.
public interface CRUDOperace {
public void vytvorObjednavku(Objednavka objednavka);
public void smazObjednavku(Objednavka objednavka);
public void aktualizujObjednavku(Objednavka objednavka);
public Objednavka nactiObjednavku(Serializable identifikator);
}
public interface ProcesniOperace {
public void zpracujObjednavku(Serializable identifikator);
public void zrusObjednavku(Serializable identifikator);
}
public interface ObjednavkovaSluzba extends CRUDOperace, ProcesniOperace {
}
The split gives clients different views of one facade (CRUD operations, processing operations or the whole thing). It also lets us give each responsibility its own implementation. We can put the complete functionality together, for example, by composing and delegating to those implementations.
public class CRUDOperaceImpl implements CRUDOperace {
//...implementace vynechána
}
public class ProcesniOperaceImpl implements ProcesniOperace {
//...implementace vynechána
}
public class ObjednavkovaSluzbaImpl implements ObjednavkovaSluzba {
private CRUDOperace crudDelegate;
private ProcesniOperace procesniDelegate;
public void vytvorObjednavku(Objednavka objednavka) {
crudDelegate.vytvorObjednavku(objednavka);
}
public Objednavka nactiObjednavku(Serializable identifikator) {
procesniDelegate.nactiObjednavku(identifikator);
}
//...zbytek vynechán
}
With this simple exercise, we’ve broken the God object into smaller parts that are easier to manage, while keeping a single interface for the central functionality. The refactored interface is also backward compatible for API clients, so we don’t have to worry about breaking anything.
Related articles
Related CZ Podcast episodes
- #261 · Leadership
On leading people and teams. · Czech audio
- #3 · Java 6 SE, Vývoj webových aplikací
Dagi and Filemon discuss Java 6 and web application frameworks. · Czech audio
- #1 · Vývojová prostředí v Javě
The first CZ Podcast episode looks at Java development environments. · Czech audio