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 of 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 we 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.