First, we will focus on the union design pattern between ABall, WanderBall, CurveBall and StraightBall. In a union design pattern, we see that the superclass represents an abstraction of the union of its subclasses. For instance, a fruit is an abstraction of specific concrete classes such as apple and pear. A fruit embodies the common characteristics of its subclasses even if it doesn't completely describe the exact nature of those characteristics. In a fruit, there is a seed. However, the notion of "fruit" doesn't specify exactly the number, size, color or shape of its seed(s). It only specifies that it does indeed have a seed. Likewise, a fruit has the behavior of ripening. Apples, oranges, and bananas all ripen differently and at different rates. The abstract fruit notion does not specify the specific nature of the ripening behavior, just simply that it does have that behavior. In such, we see that we can never have a fruit that is not a specific class of fruit, such as an orange or grape.
Corresponding to the above notions, abstract classes in Java cannot be instantiated. Abstract classes are denoted by the abstract keyword in the class definition:
public abstract class AFruit {...} In Ballworld, ABall is an abstract class representing a circular ball that has a number of properties: a color, a position, a velocity, etc. The abstract ball also has some defining behaviors, such as that all balls should paint a filled, colored circle when requested to display themselves on a graphics context (a panel). Likewise all balls know how to bounce off the walls of the container. These concrete behaviors are called "default behaviors" because all subclasses of ABall, such as StraightBall and CurveBall, automatically get these behaviors by default. One of the most common and useful reasons for using an abstract class is to be able to define the default behaviors for all the subclasses.
Abstract Methods
But what about the abstract behaviors that abstract classes exhibit? For instance the abstract "ripening" behavior of a fruit? At the abstraction level of a fruit, the exact implentation of ripening cannot be specified because it varies from one concrete subclass to another. In Java, this is represented by using the keyword abstract as part of the signature of a method which has no code body:
public abstract class AFruit {
// rest of the code
public abstract void ripen();
}AFruit. The specific implmentation of method is left to the subclasses, where the method is declared identically except for the lack of the abstract keyword:
public class Mango extends AFruit {
// rest of code
public void ripen() {
// code to ripen a mango goes here
}
}
public class Tomato extends AFruit {
// rest of code
public void ripend() {
// code to ripen a tomato goes here
}
}Note that if a class has an abstract method, the class itself must be declared abstract. This simply because the lack of code in the abstract method means that the class connot be instantiated, or perhaps more importantly, it says that in order for a class to represent abstract behavior, the class itsefl must represent an abstract notion.
Overriding is not limited to abstract methods. One can override any concrete method not declared with the final keyword. We will tend to avoid this technique however, as the changing of behavior as one changes abstraction levels leads to very unclear symantics of what the classes are actually doing.
In Ballworld we see the abstract method updateState. Abstract methods and classes are denoted in UML diagrams by italic lettering. This method is called by the update method as part of the invariant process of updating the condition of the ball every 50 milliseconds. The update method does 4 things:
- Update the state of the ball by calling the abstract
updateStatemethod. - Move (translate) the position of the ball by adding the velocity to it.
- Check if the ball needs to bound off a wall.
- Paint the ball up on the screen.
ABall.updateState() is abstract because at the abstraction level of ABall, one only knows that the ball will definitely do something with regards to modifying (perhaps) its internal field values(its "state"). Each subclass will do it differently however. The StraightBall will do nothing in its updateState method because a ball with a constant (unchanging) velocity will travel in a straight line. Remember, doing nothing is doing something! The CurveBall's updateState method uses sines and cosines to turn the velocity by a fixed (though randomly chosen) angle at every update event. You can imagine that other possible subclassses could do things such as randomly change the velocity or change the radius of the ball or change the color of the ball.
There is no code in the entire Ballworld system that explicitly references any of the concrete ABall subclasses. All of the code runs at the level of abstraction of an abstract ball. The differences in behavior of the various balls made on the screen using the different concrete subclasses is strictly due to polymorphism. New types of balls can be added to the system without recompiling any of the existing code. In fact, new types of balls can be added without even stopping the Ballworld program!










"Accessible versions of this collection are available at Bookshare. DAISY and BRF provided."