The physics department would like for us to write a simple "ball world" program that it can use to teach the idea of friction. In this program, we need for some Balls to decelerate. Every time one of these decelerating balls moves, its speed decreases by 1%.
Add a DeceleratingBall class to the Ball hierarchy for this purpose.
After adding a new subclass, we have the following Ball hierarchy:
We create a DeceleratingBall just as we would a Ball:
DeceleratingBall b = new DeceleratingBall( 10, 15, 5, 5.0, 10.0 );
After running the program, the physics department tells us that some decelerating balls need to bounce of the walls they hit, too. So we need a class of BoundedBalls that decelerate.
Fix the problem.
Here is another simple solution:
Our approach to this family of problems is straightforward: implement a decelerating version of any Ball class that needs a decelerating counterpart.
What are the strengths of this approach?
What are the weaknesses of this approach?
You may be asking yourself, "So what? It works."
What happens if we need to change the deceleration factor, say, from 1% to 2%?
We must remember to make the change
in two different classes.
What happens if we need to add deceleration behavior to other Balls?
Yes, there are several.
What happens if we need to add another kind of behavior to our ball classes, including the decelerating balls?
Even more subclasses!
Solutions that make future extensions to a program unbearable are probably not very good solutions at all...
BoundedBalls respond to the same set of messages as Balls.
So they are substitutable for one another.
Can we use this to our advantage?
Take a look at this solution.
Now, we create a DeceleratingBall by giving it a Ball to direct:
DeceleratingBall b = new DeceleratingBall( new Ball( 10, 15, 5, 2.0, 5.0 ) );
How does a DeceleratingBall work now?
This approach takes advantage of substitutability. It creates an object that delegates most of its responsibilities to another object... without the client knowing the difference!
Our new ball hierarchy looks like this:
What are the weaknesses of our new approach?
What are the strengths of our new approach?
We sometimes choose a more complex solution when it offers extensibility and flexibility as benefits.