«Code should grow by addition rather than mutation.»
The best example of that axiom I ever found is the one in Beck’s Implementation patterns. What goes next is almost an exact reproduction of the book. After reading this post, if you liked, I’d strongly recommend you to buy a copy.
Imagine a graphic editor where one of the main metaphors is the Figure. It has methods like display(). So, if you want to support several figures in the editor, you can start by writing just a simple conditional:
public void display() { switch (getType()) { case RECTANGLE : //... break; case OVAL : //... break; case TEXT : //... break; default : break; } }
This naïve example, shows early its cons: if you want to add a new kind of figure, you will need to modify the GraphicEditor class adding a new case statement in every switch you have written along the class. Not only it is tedious and error-prone, but it also requires modify a working functionality, putting it at risk. Besides, you should coordinate the changes with other developers using that class. At this point, likely you have thought on better ways to manage change: make the code growth by addition rather than mutation. How is that? Well, two of the tools you have available are inheritance (using classes) and delegation (using interfaces):
If you should choose one of another is a matter of context. It depends. For example, if you would want to rewrite the display method using delegation you would write:
public void display() { getType().display(); }
while let the rectangle and other figures to implement the logic of displaying themselves.
This change will allow us to add new kind of figures dinamically. We will only need to implement the Figure interface and use the mechanisms of GraphicEditor to select our new figure. No needs to change the existent code neither coordination costs or try to understand the whole picture before making any change. Just need to focus on implementing our tool. That’s the power of designing for growth: managing complexity.
Leave a Reply