August 17, 2004

Adaptable Pattern

The Eclipse core makes use of the Adapter Pattern (GOF) in a really interesting way to allow for further extensions to core interfaces without requiring recompiles, or interface extension bloat. You can add new functionality to implementors of existing interfaces without having to modify every derivative type in and outside of Eclipse.

The idea is that you create an interface IAdaptable:

public interface IAdaptable {
    Object getAdapter(Class adapter);
}

and have your application interfaces extend it, eg:

public interface IProcess extends IAdaptable {
  // ... IProcess interface method declarations
}

You then go ahead and write your normal functionality.

With this in place, lets see how in the future the Adapter pattern allows us to extend new functionality into the IProcess interface. Let's create a concrete Adapter implementation:

public interface SuspendableProcess {
    void suspend();
}
public class SuspendableProcessImpl implements SuspendableProcess {
    public SuspendableProcessImpl(IProcess process) {
        this.process = process;
    }
    public void suspend() {
        // implementation to suspend the process....
    }
}

All that's required now is the implementation of the getAdapter() method on IProcess.

A simple implementation could be:

public Object getAdapter(Class adapter) {
  if (adapter.equals(SuspendableProcess.class) {
    return new SuspendableProcessImpl(this);
  }
  return null; // or pass it to a super implementation
}

Clients can then get access to the new functionality by doing the following:

IProcess process = .... // retrieve reference to process instance
SuspendableProcess suspendable = (SuspendableProcess) process.getAdapter(SuspendableProcess.class);
suspendable.suspend();

Nice - we've added new functionality to the IProcess interface without having to modify all classes that implement it.

All is not yet finished, the getAdapter() method isn't quite production ready, to add new Adapters we still have to modify the getAdapter() method to define concrete types which requires recompiling all the time. Eclipse uses the concept of an AdapterFactory to solve this, eg:

public interface IAdapterFactory {
    Class[] getAdapterList();
    Object getAdapter(Object adaptableObject, Class adapterType);
}

and an AdapterManager to register factories as adapters for particular interfaces, eg:

IAdapterManager manager = Platform.getAdapterManager();
manager.registerAdapters(new SuspendableProcessAdapterFactory(), IProcess.class);

This lets us have a generic IProcess.getAdapter() implementation that simply passes the request for the adapter to the manager to fulfill.

Quite cool stuff :)

Posted by crafterm at August 17, 2004 12:08 PM | TrackBack
Comments
Post a comment









Remember personal info?