Java interfaces are a wonderful thing; don’t get me wrong. However, many interface contracts make assumptions about how the implementation will behave. What is more, Java offers no way to programmatically enforce such an interface contract.

This article discusses a particular example of interface behavioral assumption and how to (partially) enforce the behavior programmatically.

In this case, consider an interface method that specifies a return value, such as:

public interface Namable
{
    /**
     * Get the name of this object
     */
    public String getName();
}

Implementing this interface is deceptively simple – just return whatever “name” is appropriate. However, the contract is missing several behavioral rules:

  • Is null a valid return type?
  • When is this method queried?
  • Is the name requested once or multiple times?
  • Can the name change during the lifetime of the implementation?

In many cases, the assumption is that the method will always return the same value. Java interfaces offer no programmatic way to directly enforce such a behavioral contract. To improve code reliability, I’ve often resulted to creating a so-called default implementation that enforces the contract:

public final class DefaultNamable implements Namable
{
    private final String mName;
 
    public DefaultNamable(String name)
    {
        mName = name;
    }
 
    public final String getName()
    {
        return mName;
    }
}

Finally, actual implementation classes can implement the interface, dispatching to the contained default implementation:

public final class SomeNamableEntity implements Namable
{
    private final Namable mNamable;
 
    public SomeNamableEntity(String name)
    {
        mNamable = new DefaultNamable(name);
    }
 
    public String getName()
    {
        return mNamable.getName();
    }
}

Of course, this Namable example is too simplistic to really need a DefaultNamable implementation. This pattern can assist with more complex interface implementations, which require more internal data structure bookkeeping and/or have more subtle contract requirements.

As an alternative, instead of the final DefaultNamable class, create an abstract AbstractNamable implementation (or allow DefaultNamable to be extended). Either way, SomeNamableEntity could then extend the helper implementation, avoiding the duplicate method declarations required for containment and dispatch. This works only if SomeNamableEntity does not need to extend some other class.

If anyone finds this sort of pragmatic programming practice post interesting, please leave a comment. I can ramble on like this for months…

Share and Enjoy:
  • StumbleUpon
  • Facebook
  • Twitter
  • Digg
  • del.icio.us
  • Reddit
  • Technorati
  • Google Bookmarks
  • Slashdot
  • N4G