Skip to content Skip to navigation

OpenStax_CNX

You are here: Home » Content » Ballworld, composition-based

Navigation

Recently Viewed

This feature requires Javascript to be enabled.

Tags

(What is a tag?)

These tags come from the endorsement, affiliation, and other lenses that include this content.
 

Ballworld, composition-based

Module by: Stephen Wong, Dung Nguyen. E-mail the authors

Summary: The module uses the Ballworld program to demonstrate key ideas in abstract classes, polymorphism, inheritance and other coding techniques. In particular, this module will contrast a composition-based architecture with an inheritance-based architecture.

Note: You are viewing an old version of this document. The latest version is available here.

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.

The Problem with Inheritance

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 just get 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.

Pizzas and Shapes

To understand what we can do to remedy the problems with our inheritance-based model, let's digress fro 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.

Figure 1: A pizza has-a shape, which is able to calculate its area.
Pizzas and Shapes
Pizzas and Shapes (pizza.png)
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.

From Inheritance to Composition

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 wa 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.
Figure 2: Ball is now a concrete class and its subclasses have been eliminated in favor of being composed with an abstract strategy.
Composition-based Ballworld
Composition-based Ballworld (uml.png)
(Note that the Randomizer class has been redesigned to eliminate its static methods.)

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.
    • 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 peristent 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.

Content actions

Download module as:

Add module to:

My Favorites (?)

'My Favorites' is a special kind of lens which you can use to bookmark modules and collections. 'My Favorites' can only be seen by you, and collections saved in 'My Favorites' can remember the last module you were on. You need an account to use 'My Favorites'.

| A lens I own (?)

Definition of a lens

Lenses

A lens is a custom view of the content in the repository. You can think of it as a fancy kind of list that will let you see content through the eyes of organizations and people you trust.

What is in a lens?

Lens makers point to materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

Who can create a lens?

Any individual member, a community, or a respected organization.

What are tags? tag icon

Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

| External bookmarks