Build Interface Implementation Pairs

This is a simple design technique that exploits Java's language features.

In other OO languages like C++ or Smalltalk, designing a class is a single effort. There are some differences:

In C++, variables are typed to the class of the object that they can hold. That means that you end up with a lot of abstract classes that define interfaces, and then typing your variables to match these abstract classes.

In Smalltalk, variables are untyped (or dynamically typed). A programmer ends up relying on the fact that "any object that responds to these N messages" will work.

In Java, there's a way to handle abstract implementation that's different from both previous approaches. We've found that in many cases you want to build the following:

When you need an object that responds to those messages, you type the variable to the Interface, not to the class. That way, if someone finds a need to completely replace the code of the Implementation class with something else, they can simply implement the interface, and do not need to extend the class.

KenAuer has used this idiom extensively in his Java version of the venerable HotDraw framework [1].

I can think of two specific uses of this pattern in the database broker layer for Java that I'm writing now. (See CrossingChasms) In one place we substitute a Proxy for an actual class where the instance of the class has not yet been loaded from the database. To make this work we need to define each class that is "Proxyizable" as having an Interface that corresponds to its public protocol. All variables in the program then need to be typed to the Interface rather than to the actual class - this makes it possible to then transparently substitute a Proxy at any time.

In another part of the framework, I specify the Interface that any object must correspond to to be persistent. We also provide an implementation of these methods in a default base class (Persistent Object), but if a programmer wants his class to be persistent AND descend from some other class than our Persistent Object class, they can simply state that it implements the Persistency interface, and reimplement the methods themselves. The framework is written to take advantage of this, and will not care one way or another.


I think that multiple inheritance, and this use of Java's interfaces, map to adjectives, and am delighted to see people using adjectives. I also think adjectives and interface definitions map to TrygveReenskaug's RoleModeling, as each represents a role the class can play. -- AlistairCockburn.


Although Java's "interface" keyword makes the idea more conceptually explicit, I think it's important to point out that this idiom has also been used extensively in C++ (the "Interviews" GUI toolkit is one example, and I've seen RobertMartin and JohnLakos describe this technique as well).

In C++, one creates a "pure" abstract base class or "pure ABC" (an abstract class having nothing but pure virtual functions with no implementations). This pure ABC serves precisely the same function as a Java interface. Then another abstract base class is declared as a subclass of the pure abstract base. This subclass provides the "default" behavior and state that will be used by most concrete classes. In fact, having the ABC be derived from the pure ABC is *exactly* equivalent in Java to having an abstract class which declares itself to implement an interface.

The bottom line is that Java interfaces are no different from a pure ABC in C++. Java makes the interface concept explicit (which is a boon to those who haven't already seen it before and/or haven't used them in this manner), but the way Java implements them is no different than using the C++ class construct strictly for inheritance of behavioral specification (and not for behavioral implementation nor for data/state).

Now - if Java had *full* polymorphism (like Smalltalk) and it was possible to send a message to (invoke a method of) any object capable of servicing that message request, then one could use Java interfaces as method parameters without forcing the actual parameter to be an instance of a class (or subclass of a class) that is explicitly declared to implement the interface. As long as the object implemented all those methods, the formal declaration of satisfying the contract wouldn't be required. I believe this is how the "Signature" feature of GnuCpp works when you enable it with the '-fsignatures' command-line option. The java.lang.reflect package can be used to achieve this functionality, but it is considerably more effort.

Of course this "ability" would introduce some risks/concerns for security and type-safety, but it would also add a lot more flexibility and power. This is especially handy in cases where you dont have access to library source code and can't change a class just so it is declared to implement an interface that it already has all the methods for (which might be the case for simple mixin-style classes that have very few methods). See ExtendToImplementInterfaces for another way of solving this problem using Java. -- BradAppleton


This naturally extends one step further... you can adopt a convention of specifying members through private getter/setter pairs in the "implementation" part, but never specifying state (declaring members) in the implementation (and interface) classes. Then make the root(s) of the implementation hierarchy specify a single member called "State", an instance of a descendent of an abstract "Type" class.

Each implementation, in order to be instantiated, is then instantiated with a member of a given Type descendent in its "State" member. By convention (or with tools...<grin>), the Type descendent associated with a given Implementation provides an implementation of each of the private getter/setter pairs defined in the Implementation descendent and all its ancestors (let's not talk about the state member itself yet).

Now, the "type" hierarchy is separated from the "class" hierarchy. My experience has been that the classes (Implementation and Interface) are much easier to refactor, multiple inheritance (of Implementation) works, and many nitty gritty problems in a distributed environment become significantly easier to solve. -- TomStambaugh


When I first looked at Java, I thought I would use this idiom a lot, but in reality I find I don't use it so much. The reason I don't is twofold. Firstly all of these interface/implemtenation pairs are awkward to put together, adding some complexity to the design. Secondly it is easy to refactor to create the pair if it is needed later, providing you DontDistinguishBetweenClassesAndInterfaces.

The caveat with this is that it prevents a user from substituting a different class into the code. We found this when we wanted to implement our own Vector class, we had to create a new interface that replicated the Vector's interface and change all the references in our code to use the new class. Of course if we couldn't get to source code we couldn't make the change. (I suppose we might have tried fiddling with the classpath, I don't know if we could have done something there.)

If you introduce a new interface for an existing class, for which you don't have access to the source, then you need to ExtendToImplementInterfaces -- MartinFowler


I'd like to find out a bit more about your context in the above. I find what you say is often the case for small-ish stuff, or for projects with no more than 1-2 people. But when it starts getting pretty large, or you have 3 or more people, then as time goes on, I find myself having to do this anyway, and it's a bit less hassle to do it up front.

It's really not that different from using .c and .h file pairs in C (and if you don't use the ".h" files it's fairly analogous to not using the interfaces as Martin mentions above).

Even on my one person projects, I find that after a refactoring or two, it just makes my life easier to keep the interface code separate from the implementation code (both for minimal rebuilding, and more adaptable frameworks). -- BradAppleton


This is simply the Java equivalent of RobertMartin's "DependencyInversionPrinciple". In a nutshell, it just means that a concrete class should never depend on another concrete class. Abstract classes generally have more classes dependent on them. Because of simple inertia, a class with many other classes dependent upon it is forced to be more stable then a class with fewer dependencies. Thus, it is better in the long run to place an abstraction layer over any leaf nodes.

I'm confused. This seems to be saying that I'd have to put an abstract class in between a class and each of its subclasses. Suppose A is an abstract class, with concrete subclasses C1 C2 C3. Then to subclass C1 with C11, I'd first have to insert another abstract class A11 to intervene between C1 and C11??? -- RonJeffries

It is more like this: you don't accept references to objects of concrete classes anyplace, you accept references to objects of abstract classes or just interfaces. Robert's approach is almost the polar opposite of ExtremeProgramming in this respect. He tries to minimize dependency with much upfront work so that software does not have to change much in the face of change. I'm sure minimizing recompilation is a goal as well. It occurs to me that much of this approach could be a side-effect of the fact that refactoring just plain costs so much more in C++.

For anyone who is interested in seeing some philosophical differences, RobertMartin often engages in running debate on comp.object with someone named ElliottCoates?. The issues are: does OOA exist, and should code contain objects which model things in the domain or just high behavioral abstractions. -- MichaelFeathers

However, when I've tried to fully exploit this with Java's interfaces, they fail to provide adequately for non-public clients, such as Builders and Facades. Upon re-examining what I was trying to do, I find that as a C++, I am trying to use Java's interfaces to replace C++'s templates, and obviously they fail miserably at that.

What Java needs is either templates, 'friends' or some type of an ImplementationInterface? similar to Smalltalk's full polymorphism, but where the calls are validated as existing at compile time. -- ArickAnderson


You can sometimes FallBackOnReflection to BuildInterfaceImplementationPairs when the interface needs to be implemented differently by different derived classes. -- NatPryce


In DylanLanguage, you can define abstract instantiable classes. In that case, make, the generic function that handles object creation, actually returns an object of a concrete derived class. -- MichaelSchuerig


The following is probably not in the spirit of separating interface and implementation.

  interface SomeThingable
  {
     final static SomeThingable NULL = new Null();

xxx someMethod(xxx); xxx xxxx(xxx) // more methods

static class Null implements SomeThingable { xxx someMethod(xxx) { // default implementation probably do nothing } xxx xxxx(xxx) // more methods implementations. }

}

This way, clients can use SomeThingable.NULL to get a NullObject. some clients can extend SomeThingable.Null to get the default behaviour. (For instance inner classes) but there it is still an interface so classes can still choose to implement them for themselves.

A benefit of BuildInterfaceImplementationPairs is that adding methods to the interface becomes easier as many classes extend the default implementation.

(maybe you should use extended interface to do that but then you end up with lots of places where you need the extended interface but you only have the base interface. This may get very complex).


A simpler way to define SomeThingable?.NULL.

public interface SomeThingable {

  public final static SomeThingable NULL = new SomeThingable() {
    xxx someMethod(xxx); 
    xxx xxxx(xxx) // more methods     
  }; 
} -- DarJian?


CategoryInterface
EditText of this page (last edited March 2, 2006)
FindPage by browsing or searching

This page mirrored in JavaIdioms as of April 29, 2006