Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Designing with interfaces

One programmer's struggle to understand the interface

  • Print
  • Feedback

Page 3 of 6

Polymorphism means using a superclass variable to refer to a subclass object. For example, consider this simple inheritance hierarchy and code:

abstract class Animal {

abstract void talk(); }
class Dog extends Animal {
void talk() { System.out.println("Woof!"); } }
class Cat extends Animal {
void talk() { System.out.println("Meow."); } }


Given this inheritance hierarchy, polymorphism allows you to hold a reference to a Dog object in a variable of type Animal, as in:

Animal animal = new Dog();


The word polymorphism is based on Greek roots that mean "many shapes." Here, a class has many forms: that of the class and any of its subclasses. An Animal, for example, can look like a Dog or a Cat or any other subclass of Animal.

Polymorphism in Java is made possible by dynamic binding, the mechanism by which the Java virtual machine (JVM) selects a method implementation to invoke based on the method descriptor (the method's name and the number and types of its arguments) and the class of the object upon which the method was invoked. For example, the makeItTalk() method shown below accepts an Animal reference as a parameter and invokes talk() on that reference:

class Interrogator {

static void makeItTalk(Animal subject) { subject.talk(); } }


At compile time, the compiler doesn't know exactly which class of object will be passed to makeItTalk() at runtime. It only knows that the object will be some subclass of Animal. Furthermore, the compiler doesn't know exactly which implementation of talk() should be invoked at runtime.

As mentioned above, dynamic binding means the JVM will decide at runtime which method to invoke based on the class of the object. If the object is a Dog, the JVM will invoke Dog's implementation of the method, which says, "Woof!". If the object is a Cat, the JVM will invoke Cat's implementation of the method, which says, "Meow!". Dynamic binding is the mechanism that makes polymorphism, the "subsitutability" of a subclass for a superclass, possible.

Polymorphism helps make programs more flexible, because at some future time, you can add another subclass to the Animal family, and the makeItTalk() method will still work. If, for example, you later add a Bird class:

class Bird extends Animal {

void talk() {
System.out.println("Tweet, tweet!"); } }


you can pass a Bird object to the unchanged makeItTalk() method, and it will say, "Tweet, tweet!".

Getting more polymorphism
Interfaces give you more polymorphism than singly inherited families of classes, because with interfaces you don't have to make everything fit into one family of classes. For example:

interface Talkative {

void talk(); }
abstract class Animal implements Talkative {
abstract public void talk(); }
class Dog extends Animal {
public void talk() { System.out.println("Woof!"); } }
class Cat extends Animal {
public void talk() { System.out.println("Meow."); } }
class Interrogator {
static void makeItTalk(Talkative subject) { subject.talk(); } }


Given this set of classes and interfaces, later you can add a new class to a completely different family of classes and still pass instances of the new class to makeItTalk(). For example, imagine you add a new CuckooClock class to an already existing Clock family:

class Clock {
}

class CuckooClock implements Talkative {
public void talk() { System.out.println("Cuckoo, cuckoo!"); } }


Because CuckooClock implements the Talkative interface, you can pass a CuckooClock object to the makeItTalk() method:

class Example4 {

public static void main(String[] args) { CuckooClock cc = new CuckooClock(); Interrogator.makeItTalk(cc); } }


With single inheritance only, you'd either have to somehow fit CuckooClock into the Animal family, or not use polymorphism. With interfaces, any class in any family can implement Talkative and be passed to makeItTalk(). This is why I say interfaces give you more polymorphism than you can get with singly inherited families of classes.

The 'burden' of implementation inheritance

Okay, my "more polymorphism" claim above is fairly straightforward and was probably obvious to many readers, but what do I mean by, "without the burden of multiple inheritance of implementation?" In particular, exactly how is multiple inheritance of implementation a burden?

As I see it, the burden of multiple inheritance of implementation is basically inflexibility. And this inflexibility maps directly to the inflexibility of inheritance as compared to composition.

By composition, I simply mean using instance variables that are references to other objects. For example, in the following code, class Apple is related to class Fruit by composition, because Apple has an instance variable that holds a reference to a Fruit object:

class Fruit {

//... }
class Apple {
private Fruit fruit = new Fruit(); //... }


In this example, Apple is what I call the front-end class and Fruit is what I call the back-end class. In a composition relationship, the front-end class holds a reference in one of its instance variables to a back-end class.

In last month's edition of my Design Techniques column, I compared composition with inheritance. My conclusion was that composition -- at a potential cost in some performance efficiency -- usually yielded more flexible code. I identified the following flexibility advantages for composition:

  • It's easier to change classes involved in a composition relationship than it is to change classes involved in an inheritance relationship.

  • Composition allows you to delay the creation of back-end objects until (and unless) they're needed. It also allows you to change the back-end objects dynamically throughout the lifetime of the front-end object. With inheritance, you get the image of the superclass in your subclass object image as soon as the subclass is created, and it remains part of the subclass object throughout the lifetime of the subclass.


The one flexibility advantage I identified for inheritance was:

  • It's easier to add new subclasses (inheritance) than it is to add new front-end classes (composition), because inheritance comes with polymorphism. If you have a bit of code that relies only on a superclass interface, that code can work with a new subclass without change. This isn't true of composition, unless you use composition with interfaces.


In this last flexibilility comparison, however, inheritance is not as secure as it might seem given its polymorphism advantage. That last clause above, "unless you use composition with interfaces," is very important. Basically, thanks to interfaces, the composition relationship can also bask in the warm glow of polymorphism. Here's an example:

  • Print
  • Feedback

Resources
  • Bill Venners' next book is Flexible Java http://www.artima.com/flexiblejava/index.html
  • Bill Venners just got back from his European bike trip. Read about it at
    http://www.artima.com/bv/travel/bike98/index.html
  • The discussion forum devoted to the material presented in this article http://www.artima.com/flexiblejava/fjf/ interfaces /index.html
  • Links to all previous design techniques articles http://www.artima.com/designtechniques/index.html
  • Recommended books on Java design http://www.artima.com/designtechniques/booklist.html
  • A transcript of an e-mail debate between Bill Venners, Mark Johnson (JavaWorld's JavaBeans columnist), and Mark Balbe on whether or not all objects should be made into beans http://www.artima.com/flexiblejava/comments/beandebate.html
  • Object orientation FAQ http://www.cyberdyne-object-sys.com/oofaq/
  • 7237 Links on Object Orientation http://www.rhein-neckar.de/~cetus/software.html
  • The Object-Oriented Page http://www.well.com/user/ritchie/oo.html
  • Collection of information on OO approach http://arkhp1.kek.jp:80/managers/computing/activities/OO_CollectInfor/OO_CollectInfo.html
  • Design Patterns Home Page http://hillside.net/patterns/patterns.html
  • A Comparison of OOA and OOD Methods http://www.iconcomp.com/papers/comp/comp_1.html
  • Object-Oriented Analysis and Design MethodsA Comparative Review http://wwwis.cs.utwente.nl:8080/dmrg/OODOC/oodoc/oo.html
  • Patterns discussion FAQ http://gee.cs.oswego.edu/dl/pd-FAQ/pd-FAQ.html
  • Patterns in Java AWT http://mordor.cs.hut.fi/tik-76.278/group6/awtpat.html
  • Software Technology's Design Patterns Page http://www.sw-technologies.com/dpattern/
  • Previous Design Techniques articles http://www.javaworld.com/topicalindex/jw-ti-techniques.html