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(); }
There is no code body because it cannot be specified at this abstraction level. All that the above code says is that the method does exist in all 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() { 11 code to ripen a tomato goes here } }
The technical term for this process is called overriding. We say that the concrete methods in the subclasses override the abstract method in the superclass.
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 cannot be instantiated, or perhaps more importantly, it says that in order for a class to represent abstract behavior, the class itself 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 updateState method.
- Move (translate) the position of the ball by adding the velocity to it.
- Check if the ball needs to bound of a wall.
- Paint the ball up on the screen.
This technique of calling an abstract method from inside of a concrete method is called the template method design pattern - which we will get to later in the course.
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!
- 1353 reads