Use the Bridge Pattern

Interfaces allow you to use selected functionality of a class without needing to know the concrete type. An interface is perhaps the most powerful form of polymorphism. In Java, interfaces are a built-in type. In C++ interfaces are pure virtual base classes. In COM, interfaces appear as an array of function pointers. The Bridge/Impl pattern is a very effective way to simplify the use of interfaces.

When you require someone else to implement an interface, such as a callback, you should oblige them to implement as few methods as possible. Keep the methods simple and their behavior unambiguous. When you provide interfaces for others to use, they want you to provide as many convenient services as possible. Users want extra methods with default arguments, and they want robust tolerance of special cases. Most interfaces eventually have both uses. How can you avoid this conflict in priorities? You need the Bridge pattern.

Begin with the simplest methods necessary to define your functionality. For a Vector you might define methods to add another vector and to scale by a constant. These methods will constitute your implementation interface, called Impl for short. Next define a full-featured interface that has convenience methods like zero and copy. Most often, you want to derive the full-featured interface from the simple Impl interface, so that simple methods are still available. The extra methods can be coded by using only the methods in the Impl class. You can code these implementations once and for all in one place, the bridge class.

In Java your bridge class might look like

 
public interface VectorImpl {
  public void scale(double factor);
  public void add(Vector anotherVector); 
}

public interface Vector extends VectorImpl { 
  public void zero(); 
  public void copy(Vector anotherVector); 
}

public class VectorBridge implements Vector {
  private VectorImpl _vectorImpl;

  public VectorBridge(VectorImpl vectorImpl) { 
    _vectorImpl = vectorImpl;
  }

  public void scale(double factor) {
    _vectorImpl.scale(factor);
  }
  public void add(Vector anotherVector) {
    _vectorImpl.add(anotherVector);
  }
  public void zero() {
    _vectorImpl.scale(0.);
  }
  public void copy(Vector anotherVector) {
    this.zero(); _vectorImpl.add(anotherVector);
  }
} 

Most of your code will export Vector interfaces, and you will require users to implement VectorImpl. VectorBridge makes a VectorImpl look like a full-featured Vector.

In C++, you can follow the same style or you can abbreviate with an abstract class. (Some methods have implementations, and others do not.)

 
class Vector { 
public:
  virtual void scale(double factor) = 0;
  virtual void add(const Vector& anotherVector) = 0;

  virtual void zero() {
    this->scale(0.);
  }
  virtual void copy(const Vector& anotherVector) {
    this->zero(); this->add(anotherVector);
  }
  virtual ~Vector() {} 
}; 

Now we have only one interface for a vector. The three preceding classes have been combined into one. Users can override the extra methods if they have a more efficient implementation. Otherwise, they get a usable default. On the other hand, if you need only the Impl methods, a user may unnecessarily optimize unused methods.

You can code an identical abstract class in Java, but with a serious drawback. Java classes can implement any number of interfaces but can extend only one abstract class. Personally, I prefer to keep all implementation out of interfaces. There are good reasons for avoiding multiple inheritance of implementations. Nevertheless, the simplicity of adding default convenience methods is very tempting.

Bill Harlan, 1999


2009 postscript:

The Bridge is a structural pattern that was originally drawn by Gamma et al in "Design Patterns" (1994, Addison Wesley) with two abstract classes and concrete instances of each. One abstraction was intended for a client, and the other was intended for the implementation. The client abstraction accepted an instance of the implementer and delegated services to that implementer. For me, the best use of this pattern seemed obvious: separate your abstraction of what a client wants from what an implementation finds it easy to provide.

Since then, the Bridge pattern has been drawn many other ways, with different uses and intentions. For this reason, I no longer call this pattern a bridge pattern, but rather an interface decorator. See a more recent description of the approach here: [ Avoid_extending_classes.html ] .


Return to parent directory.