Composition with inner classes: A multiple inheritance substitute

The composition combined with the inner classes is an excellent substitute for the multiple-inheritance.

Tutorial | Feb 21, 2020 | nextptr 

Overview

Java does not support multiple-inheritance - it is the fact that every Java newcomer confronts, explores, and is eventually persuaded to admire. The commonly cited reason to not support the multiple-inheritance is quite straightforward: that it leads to ambiguity and complexity in classic diamond-shaped hierarchies. Conceptually speaking, the multiple-inheritance is an OOP feature to model the natural multiple-is-a relationship (A is B, and A is C), and Java provides enough simple means to accomplish it. In this article, we do not deliberate over whether Java should support multiple-inheritance or not, but instead, we present a design pattern that deftly models multiple-is-a relationships.

In Java, a class can implement many interfaces. However, an interface is a declaration, not an implementation of a behavior. Sure, since Java 8, the interfaces can have default methods, but an interface is hardly a place to define a complete behavior. The conventional approach in Java, perhaps a workaround, to design a multiple-is-a relationship is composition. In the next section, we would talk about composition and, in the latter part, refine that technique to create a better substitute for the multiple-inheritance.

Composition

The composition is a design concept to model a strong "has-a" relationship. In Java, it is implemented by a class having sole ownership of an instance of another class. Composition, along with the implementation of multiple interfaces, can be utilized to obtain a multiple-is-a behavior. Let's take an example.

Two UI classes, Clickable and Rectangle, implement their respective interfaces IClickable and IRectangle. We need to define a button class, which, in essence, is a rectangular clickable widget. So, our Button class implements both IClickable and IRectangle interfaces. The Button reuses the behavior of Clickable and Rectangle through composition, as shown in the below class diagram and the code:

interface IClickable {
 void click();
}

interface IRectangle {
 long length();
 long width();
 void draw();
 //...more methods
}

class Clickable implements IClickable {
  public void click() {
  //..handle click
  }

  //protected fields/methods here
}

class Rectangle implements IRectangle {
 public long length() { return l; }
 public long width() { return w; }
 public void draw() { 
  //..draw rectangle
 }
 //...protected methods here

 //protected fields
 protected long l, w;
 /* ...more protected fields here... */
}

The multiple-is-a behavior through composition, as shown above, has a serious limitation. The composing class (Button) can only access the public behavior of a composed class (Clickable or Rectangle). However, in real life, the classes often have protected methods and fields meant to be accessible to only inheriting-classes. Suppose, the Button needs to animate with a pressed effect when clicked. Adding this behavior to the Button requires us to override some of the Rectangle's behavior by accessing its protected fields. But the Button does not have access to the protected methods and fields of the Rectangle. Sure, we can add support of animation to Rectangle itself, but that would be adding Button specific behavior to the Rectangle. The composition can only take us this far because it is a has-a relationship concept in essence. What we need is inheritance or is-a in some form to correctly model multiple-is-a. We can do so, as we will see in the next section, by combining composition with inner classes.

Composition with Inner Classes

A Java inner class is a non-static nested class whose instance is linked to the enclosing class' object. An inner class has direct access to all the fields and methods of its enclosing object. Inner classes can be declared private to the parent class and can extend from the outside classes. Think of an inner class as a nested segment of specific behavior and data that can extend from the other classes, as shown below:

We can use inner classes with composition to emulate multiple-inheritance. We modify the Button class to define two inner classes, ExtClickable and ExtRectangle, which extend the Clickable and Rectangle, respectively. The Button comprises the instances of ExtClickable and ExtRectangle now, as shown below:

class Button 
 implements IClickable, IRectangle {

 public void click() {
  clickable.click();
  //Animate on click
  rectangle.animate();
 }

 public long length() { return rectangle.length(); }
 public long width() { return rectangle.width(); }
 public void draw() { rectangle.draw(); }

 private class ExtClickable 
  extends Clickable {
   /*
   Override Clickable behavior if required.
   Can access Clickable's protected fields/methods. 
   Can access Button's private fields/methods.
   */
 }

 private class ExtRectangle 
  extends Rectangle {

   /* Override Rectangle behavior if required.
      Can access Rectangle's protected fields/methods. 
      Can access Button's private fields/methods. */

  void animate() { 
   //..access Rectangle's protected fields/methods
  }
 }

 protected ExtClickable clickable = new ExtClickable();
 protected ExtRectangle rectangle = new ExtRectangle();
}

Note that the two inner classes are declared private. They are encapsulated and can contain the Button specific behavior. Moreover, these inner classes have all the benefits of inheritance, like, accessing the protected members and overriding the methods of the base class. Therefore, we define an animate method in ExtRectangle that can produce a button pressed effect by accessing the Rectangle's protected fields. The animate method is called from the Button's click method.

Summing Up

Java's value is in attaining high productivity through simplicity. For that cause, Java does not support multiple-inheritance. But it does provide enough elegant and straightforward features to compose a multiple-is-a relationship. In this article, we showed how the regular composition blended with the inner classes is an excellent substitute for the multiple-inheritance.

References