Designing with interfaces

One programmer's struggle to understand the interface

1 2 Page 2
Page 2 of 2

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:

interface Peelable {

int peel(); }

class Fruit {

// Return int number of pieces of peel that // resulted from the peeling activity. public int peel() {

System.out.println("Peeling is appealing."); return 1; } }

class Apple implements Peelable {

private Fruit fruit = new Fruit();

public int peel() { return fruit.peel(); } }

class FoodProcessor {

static void peelAnItem(Peelable item) { item.peel(); } }

class Example5 {

public static void main(String[] args) {

Apple apple = new Apple(); FoodProcessor.peelAnItem(apple); } }

Given the above set of classes, you could later define a class Banana like this:

class Banana implements Peelable {

private Fruit fruit = new Fruit();

public int peel() { return fruit.peel(); } }

Like Apple, class Banana has a composition relationship with Fruit. It reuses Fruit's implementation of peel() by explicit delegation: it invokes peel() on its own Fruit object. But a Banana object can still be passed to the peelAnItem() method of class FoodProcessor, because Banana implements the Peelable interface.

As this example illustrates, interfaces allow you to get the best of both worlds. You get the flexibility of composition and the flexibility of polymorphism in one design.

Choosing between composition and inheritance

As I described in last month's article, my basic approach to choosing between inheritance and composition is that I make sure inheritance models a permanent is-a relationship. The is-a relationship means that a subclass is a more specialized form of a superclass (that the superclass is a more general form of the subclass). For example, a SavingsAccount is-an Account. I believe that modeling all (and only) permanent is-a relationships with inheritance helps maximize the code flexibility, because doing so gives inheritance a clear meaning that can help other programmers understand your code.

My main design philosophy is that its primary goal should be to maximize code flexibility, defined as the ease with which code can be understood and changed. Although I state in last month's article that composition in general yields more flexible code than inheritance, I list reasons that show composition yielding code that's easier to change, but not necessarily easier to understand. Inheritance, if you use it just for is-a relationships, gives you the flexibility advantage that your code becomes easier to understand.

My feeling, therefore, is that the way to get maximum advantage of both inheritance and composition in your designs is to ask yourself if you have a permanent is-a relationship. If so, use inheritance. If not, use composition. For more details on this design guideline, read last month's article.

Interface guidelines

Where, then, do interfaces fit into this picture? As I mention above, one major benefit of the Java interface is that they give composition a shot at polymorphism. When you use composition with interfaces, it becomes as easy to add a new front-end class (composition) as it is to add a new subclass (inheritance). But what does this tell us? Should you always use interfaces every time you use composition? Well, no. Should you avoid using interfaces in conjunction with single inheritance of class extension? Certainly not.

As I mentioned at the beginning of this article, it took me a long time to get the point of interfaces. The epiphany finally came when I recognized that separation interface and implementation is one of the primary ideas behind Java in general. The Java virtual machine (JVM), for example, is an abstract computer that defines the way your program "interfaces" with the underlying real computer. A JVM that runs on Windows is one implementation of that abstract computer. A JVM that runs on the Macintosh is another. A JVM that runs on your wristwatch is yet another.

Likewise, the Java APIs are designed not to give you access to specific capabilities of particular computers and operating systems, but define abstract interfaces through which your programs talks to the underlying concrete computer and operating system, whatever it is. Swing, for example, provides an interface through which your Java program can create graphical user interfaces on whatever platform happens to be underneath. You can even use Swing to create user-interfaces on your wristwatch, so long as someone has done the work to implement Swing on your wristwatch.

Separation of interface and implementation is central to Java's spirit, and the Java interface construct enables you to achieve this separation in your designs. Two major activities of any software system design are identifying parts (the subsystems within a program or system of programs) and specifying the interfaces between the parts. In designing a Java-based system, you should use Java interfaces to represent abstract interfaces -- the ways in which the parts will interact with each other.

So this is how I ended up thinking about Java's interfaces: as the preferred means of communicating with the parts of your program that represent abstractions that may have several implementations. For example, two parts of a program I describe in my September Design Techniques installment, "The Event Generator Idiom", were TelephoneListener and Telephone. In this design, I decided that the "telephone listener" represented an abstraction that could have multiple implementations, but that Telephone did not. Thus, I made Telephone a class that didn't implement any interfaces, and defined TelephoneListener as an interface. Telephone, an event source, passed events to (communicated with) listeners through the TelephoneListener interface.

I see interfaces as a fundamental tool for achieving flexibility in the design of Java-based systems. Any class can provide an implementation of an interface. As long as you don't change the interface itself, you can make all kind of changes to the implementing classes, or plug in new classes, without impacting code that depends only on the interface. Thus, if you have a subsystem that represents an abstraction that may have multiple implementations, whether the subsystem is a single object, a group of objects, an entire Java applet or application, you should define Java interfaces through which the rest of the world communicates with that subsystem. When you use interfaces in this way, you decouple the parts of your system from each other and generate code that is more flexible: more easily changed, extended, and customized.

Next month

In next month's Design Techniques article, I'll talk about designing with dynamic extension.

A request for reader participation

I encourage your comments, criticisms, suggestions, flames -- all kinds of feedback -- about the material presented in this column. If you disagree with something, or have something to add, please let me know.

You can either participate in a discussion forum devoted to this material, enter a comment via the form at the bottom of this article, or e-mail me directly, using the link provided in my bio below.

Bill Venners has been writing software professionally for 12 years. Based in Silicon Valley, he provides software consulting and training services under the name Artima Software Company. Over the years he has developed software for the consumer electronics, education, semiconductor, and life insurance industries. He has programmed in many languages on many platforms: assembly language on various microprocessors, C on Unix, C++ on Windows, Java on the Web. He is author of the book: Inside the Java Virtual Machine, published by McGraw-Hill.

Learn more about this topic

  • 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
1 2 Page 2
Page 2 of 2