Inheritance and delegation in Java

Instructor's Guide


intro polymorphism idioms patterns events summary, Q/A, literature
Consider the example below, an envelope class that offers a message method. In this form it is nothing but a variation on the hello world example presented in the appendix.
  public class envelope { 
envelope
public envelope() { } public void message() { System.out.println("hello ... "); } };

slide: Hello World

To illustrate the idea underlying idioms and patterns in its most simple form, we will refine the envelope class into the collection of classes depicted in slide 2-envelope-letter.

We will proceed in three steps: (1) The envelope class will be redesigned so that it acts only as an interface to the letter implementation class. (2) Then we introduce a factory object, that is used to create envelope and letter instances. (3) Finally, we refine the letter class into a singleton class, that prevents the creation of multiple letter instances.



slide: Envelope/Letter Factory

Envelope/Letter

The Envelope/Letter idiom was introduced in  [Coplien92] as a means to separate interface aspects from implementation aspects. Here the call to message is simply forwarded to the letter object.
  public class envelope { 
envelope
letter impl; public envelope() { impl = new letter(); } public void message() { impl.message(); } };
  public class letter { 
letter
public letter() { } public void message() { System.out.println("Message in a letter"); } };

slide: Envelope/Letter

Admittedly, there is no need here to make such a distinction, but the idea speaks for itself. As you will see, this distinction allows us to change the implementation without modifying the envelope or interface class.

Factory

In the next refinement, we introduce a factory object, that allows us to create envelope and letter instances without invoking a constructor.
  public class factory { 
factory
public factory() { } letter letter() { return new letter(); } envelope envelope() { return new envelope(); } };
  public class envelope { 
envelope
letter impl; public envelope() { factory f = new factory(); impl = f.letter(); // obtained from factory } public void message() { impl.message(); } };

slide: Factory

The factory object is used in the envelope class to create a letter. The advantage here, as will be shown shortly, is that the envelope class does not need to have any information about the actual type of the letter.

Singleton letter

Finally, we refine the letter class into a singleton class. When you inspect the implementation, you will see that only one instance of a letter will be created.
  public class singleton extends letter {  
singleton
static int number = 0; protected singleton() { } static letter instance() { if (number==0) { theletter = new letter(); number = 1; } return theletter; } public void message() { System.out.println("Message in a letter"); } static letter theletter; };

slide: Singleton letter

Note that the factory object must be modified so that the static method instance of singleton is invoked instead of the original constructor of letter.

Discussion

This example, however simple, demonstrates the implementation of some of the idioms and patterns that will be discussed in the rest of this chapter. It shows that the basic mechanisms of inheritance and simple delegation or forwarding are sufficient to implement these idioms and patterns. We have not discussed yet why we need idioms and patterns, but this will hopefully become clear later on.