<< Chapter < Page | Chapter >> Page > |
In this module we will explore what is gained by modifying the inheritance-based Ballworld system into a composition-based system.
In the inheritance-based Ballworld system, we were able to generate quite a bit of flexibility and extensibility. For instance, we could develop new kinds of balls and add them into the system without recompiling the rest of the code. This was accomplished by having the invariant ball creation and management code deal only with the abstract ball while the variant behaviors were encapsulated into the concrete subclasses.
Inheritance seems to work quite well, but suppose we want to do more than just put different kinds of balls on the screen? What if we wanted to be able to change how a ball behaves, after it has been created? What if we want create balls that do a multiple of different behaviors, such as change color and radius? While working solutions using an inheritance-based system do exist, they are cumbersome, inefficient and most importantly, inconsistent with any sort of clear abstract model of what balls should be like.
The problem lies in the very nature of inheritance. When we attempted to separate the variant from the invariant behaviors, we overlooked a crucial aspect of inheritance. In our model, the superclass represented the invariant behaviors of a ball while the subclasses represented the variant behaviors. The separation seemed clear enough in the UML diagram, except that when one has an actual object
instance ,
both the superclass and subclass behaviors are bound into a
single entity. A ball
object cannot change its variant
updateState
behavior because it is inextricably bound with to the invariant behaviors. A ball object cannot be composed of multiple
updateState
behaviors because that code cannot be isolated from the rest of the ball's code. If you want a curving behavior, you have to get it packaged in a whole ball object--you can't get just the behavior.
A clear sympton of this problem is the common code to call the superclass constructor found in all the subclasses' constructors. This tells us that the superclass is really right there in the subclass with everything else. The fact that the code is repeated from class to class says that it is invariant code in the middle of what we want to be variant code.
The inheritance-based model of Ballworld does not separate the variant and the invariant at the proper place. There is invariant code mixed together with the variant code.That's why they can't be separated and the invariant behaviors are dragged along with the variant behaviors. This is what makes dynamically changing behaviors and multiply composed behaviors so difficult in this system.
To understand what we can do to remedy the problems with our inheritance-based model, let's digress for a bit and consider a simple model of pizzas. Here, we have a pizza which has a price and
has a shape. A shape, be it a circle, square, rectangle of triangle, is capable of determining its own area. A pizza, when requested to calculate its price per square inch, simply takes its price and divides it by the area of its shape. To obtain that area, the
Pizza
delegates to the
IShape
, since it is the shape that knows how to calculate its area, not the pizza.
Delegation is the handing of a calculation off to another object for it process. Here, the pizza is only interested in the result of the area calculation, not how it is performed.
To the pizza, the shape represents an abstract algorithm to calculate the area.The
Pizza
and the
IShape
classes represent the invariant processes involved with calculating the price per square inch ration, while the concrete
Circle
,
Square
,
Triangle
and
Rectangle
classes represent the variant area calculations for different shapes. What wee see from this example is that
objects can be used to represent pure behavior, not just tangible entities.Interfaces are particularly useful here as they are expressly designed to represent pure, abstract behavior.
Notification Switch
Would you like to follow the 'Principles of object-oriented programming' conversation and receive update notifications?