Tags

, , , ,

When designing software it’s very likely we will have to face up decisions like: should I define this type using an interface or should I use an abstract class?  Of course, as for the most engineering questions, we should answer with: it depends!

In Java, the most obvious difference between using an interface and using an abstract class is that the latter allows us to define some default behavior implementing some methods in the parent class. This is not possible in interfaces. But there is another important issue that should draw our attention before making a decision: Java permits only single inheritance, for this reason, most of the time, an interface should be the one to be preferred.

There is an exception to this rule and it comes from the fact that an abstract class is far easier to evolve than an interface. If, after some time, we want to add a new method in an abstract class we can always add a concrete method containing a default implementation. The concrete classes extending the abstract class will then decide to override this method or not. With an interface we cannot add a method without breaking all the classes that implement the interface.

The author of Effective Java, Joshua Bloch, stresses the pros of preferring interfaces over abstract classes. For example, when some classes already extend from an abstract class and we want only some of them to extend from a new type, using an abstract class means placing it high up in the type hierarchy. This causes great collateral effects, forcing all descendants to extend the new abstract class whether or not it is appropriate. This doesn’t happen when using an interface, which can be placed in any point of the hierarchy because there is not single-inheritance limit.

But how can we provide default behavior if we choose to use interfaces, which cannot contain implemented methods? Fortunately there is a simple technique, we can use the so-called: skeletal implementation.

In this scheme, we will keep using an interface to define a type and we introduce a skeletal abstract class which will implement the interface and will provide some default behavior. This way we are “providing the implementation assistance of abstract classes without imposing the severe constraints that abstract classes impose when they serve as type definitions” (Joshua Bloch).

uml class diagram skeletal

We created a situation where extending the abstract class is strictly optional. In cases where a class cannot  be made to extend the skeletal, it can always implement the interface. Furthermore, using composition instead of Inheritance, the class can always use the skeletal implementation forwarding invocations to a contained instance of a private inner class that extends the skeletal:

// Concrete implementation built atop skeletal
public class ConcreteType implements InterfaceType{
    // composite - private skeletal instance
    private MySkeletal mySkel = new MySkeletal();

    @Override
    public void methodA() {
       mySkel.methodA();
    }

    @Override
    public int methodB() {
       return mySkel.methodB();
    }

    // private inner class that extends skeletal
    private class MySkeletal extends SkeletalType {
        @Override
        public void methodA(){
            // implement abstract method
        }

        // methodB: default implementation
    }
}
Advertisements