Bridge Pattern Tutorial with Java Examples

Today's pattern is the Bridge pattern, which allows you to vary both the implementation and the abstraction by placing both in seperate class hierachies.

Bridge in the Real World 

The display of different image formats on different operating systems is a good example of the Bridge pattern. You might have different image abstractions for both jpeg and png images. The image structure is the same across all operating systems, but the how it's viewed (the implementation) is different on each OS. This is the type of decoupling that the Bridge pattern allows.

Design Patterns Refcard
For a great overview of the most popular design patterns, DZone's Design Patterns Refcard is the best place to start. 

The Bridge Pattern

The Bridge pattern is known as a structural pattern,as it's used to form large object structures across many disparate objects. Thedefinition of Bridge provided in the original Gang of Four book on DesignPatterns states: 

Decouple an abstraction from its implementation so that the two can vary independently

Let's take a look at the diagram definition before we go into more detail.

Image title


The Abstraction defines the abstraction, and maintains the reference to the implementor.  RefinedAbstraction provides an extension to the Abstraction, usually adding extra methods that provide different ways of getting at the same functionality. The Implementor interface defines an interface for the implementation classes (the ConcreateImplementor classes).



RefinedAbstractions are implemented in terms of the abstraction, and not that implementation interface.This means that the implementation details are hidden from the client. The pattern is similar to the Adapter pattern, except the Bridge pattern separates the interface from implementation.

Would I Use This Pattern?

The Bridge pattern should be used when both the class as well as what it does vary often. The bridge pattern can also be thought of as two layers of abstraction. When the abstractions and implementations should not be bound at compile time, and should be independently extensible the pattern should be used. 

In particular this pattern is useful in graphic toolkits that need to run on multiple platforms. You'll  see this in AWT, where a component has a component peer which does the OS specific operations. Also the Collections framework has examples of the bridge interface: ArrayList and LinkedList are implement List. And List provides common methods to add, remove or check size. 

So How Does It Work In Java?

Here's the pattern in action using the remote control example from Head First Design Patterns. 

First, we have our TV implementation interface: 

//Implementor public interface TV{public void on();public void off(); public void tuneChannel(int channel);}

 And then we create two specific implementations - one for Sony and one for Philips: 

//Concrete Implementor public class Sony implements TV{public void on(){//Sony specific on}public void off(){//Sony specific off}public void tuneChannel(int channel);{//Sony specific tuneChannel}}//Concrete Implementor public class Philips implements TV{public void on(){//Philips specific on}public void off(){//Philips specific off}public void tuneChannel(int channel);{//Philips specific tuneChannel}}

 These classes deal with the specific implementations of the TV from each vendor. 

Now, we create a remote control  abstraction to control the TV:

//Abstractionpublic abstract class RemoteControl{   private TV implementor;          public void on()   {      implementor.on();   }   public void off()   {      implementor.off();   }      public void setChannel(int channel)   {   implementor.tuneChannel(channel);   }}

 As the remote control holds a reference to the TV, it can delegates the methods through to the interface. But what is we want a more specific remote control - one that has the + / - buttons for moving through the channels? All we need to do is extend our RemoteControl abstraction to contain these concepts: 

//Refined abstractionpublic class ConcreteRemote extends RemoteControl{   private int currentChannel;       public void nextChannel()   {       currentChannel++;   setChannel(currentChannel);   }      public void prevChannel()   {       currentChannel--;   setChannel(currentChannel);   }      }

Watch Out for the Downsides

One of the major drawbacks of this pattern is that, in providing flexibility, it increases complexity. There's also possible performance issues with the indirection of messages - the abstraction needs to pass messages along to the implementator for the operation to get executed.

Next Up

More patterns later this week - we're close to the end now!

Enjoy the Whole "Design Patterns Uncovered" Series:

Creational Patterns

Structural Patterns

Behavioral Patterns

 

 

 

 

Top