You are here

From Inheritance to Composition

26 July, 2019 - 09:51
Available under Creative Commons-ShareAlike 4.0 International License. Download for free at http://cnx.org/contents/402b20ad-c01f-45f1-9743-05eadb1f710e@37.6

Coming back to Ballworld, we see that the updateState method in ABall is an abstract algorithm to update the state of the ball. So, just as in the pizza example, we can represent this algorithm, and just this algorithm, as an object. We can say that a ball has an algorithm to update its state. Another way of saying this is to say that the ball has a strategy to update its state. We can represent this by using composition. Instead of having an abstract method to update the state, we model a ball as having a reference to an IUpdateStrategy object. The code for update thus becomes

public void update(Observable o, Object g) {  _strategy.updateState(this); // update this ball's state using the strategy     location.translate (velocity.x, velocity.y); // move the ball   bounce(); // bounce the ball off the wall if necessary   paint((Graphics) g); // paint the ball onto the container } 

The ball hands a reference to itself, this, to the strategy so that the strategy knows which ball to update. The variant updating behaviors are now represented by concrete implementations of the IUpdateStrategy interface.

media/image7.png
Figure 2.7 Composition-based Ballworld 
Ball is now a concrete class and its subclasses have been eliminated in favor of being composed with an abstract strategy. 
Note: The Randomizer class has been redesigned to eliminate its static methods. One new method has been added as well.

There are a number of very important points to notice about this new formulation:

  • The modified ABall class now contains 100% concrete code and thus should not be abstract anymore.
    • ABall has been renamed to simply Ball.
    • Accessor methods for the strategy (getStrategy and setStrategy) have been added.
    • The Ball class is still 100% invariant code.
  • The CurveBall, StraightBall, etc. subclasses are no longer needed as their variant behaviors have been moved to the IUpdateStrategy subclasses.
    • Effectively what has happened is that the updateState method has been moved from the ABall
    • subclasses and embodied into their own classes.
    • The IUpdateStrategy subclasses do not inherit anything from Ball, hence they do not contain
    • any invariant code.
    • The strategies are thus 100% variant code.
  • The reference to the ball during the updating process has gone from a persistent communication link (implicitly, this), to a transient communication link (host).
  • This composition-based model divides the code exactly between the variant and invariant behaviors – this is the key to the power and flexibility it generates.

This new composition-based model of Ballworld is an example of the Strategy Design Pattern. The strategy design pattern allows us to isolate variant behaviors on a much finer level than simple inheritance models.