|Lesson 7||Abstract classes |
|Objective||Learn how abstract classes are close relatives of interfaces.|
Abstract Classes versus Interfaces
Java interfaces are very similar to abstract classes. An abstract class is simply a class that contains unimplemented methods.
When a class is derived from an abstract class it must implement all of the unimplemented methods declared in the abstract class.
Unlike interfaces, abstract classes can contain member variables and implemented methods in addition to unimplemented methods.
This makes abstract classes more powerful than interfaces in some respects.
Java does not support multiple inheritance, which means that you can not derive a class from more than one parent class, including abstract classes.
On the other hand, classes can implement as many interfaces as they want.
This is a critical difference between interfaces and abstract classes, and ultimately makes interfaces more useful than abstract
classes in most situations. For this reason, the Java API relies heavily on interfaces but uses abstract classes sparingly.
Class versus interface
I use interfaces when I see that something in my design will change frequently.
For example, the Strategy pattern lets you swap new algorithms and processes into your program without altering the objects that use them.
A media player might know how to play CDs, MP3s, and wav files.
You do not want to hardcode those playback algorithms into the player because that will make it difficult to add a new format such as AVI.
Furthermore, your code will be littered with useless case statements. In addition, you will need to update those case statements each time you add a new algorithm.
With the Strategy pattern, you can simply encapsulate the algorithm behind an object.
If you do that, you can provide new media plug-ins at any time.
Let's call the plug-in class MediaStrategy. That object would have one method: playStream(Stream s).
So to add a new algorithm, we simply extend our algorithm class. When the program encounters the new media type, it simply delegates the playing of the stream to our media strategy.
Of course, you will need to write code to properly instantiate the algorithm strategies you will need.
This is an excellent place to use an interface. We have used the Strategy pattern, which clearly indicates a place in the design that will change.
Thus, you should define the strategy as an interface.
You should generally favor interfaces over inheritance when you want an object to have a certain type; in this case, MediaStrategy.
Relying on inheritance for type identity is dangerous; it locks you into a particular inheritance hierarchy.