Difference Between Adapter and Bridge Design Patterns

As I was preparing for an upcoming presentation on the topic of Design Patterns, I was studying through the different patterns and could not differentiate between the Bridge Pattern and the Adapter Pattern. Right off the bat both of those patterns fall into the category of structural patterns. Both of those patterns allow us to take advantage of the Liskov Substitution principle. Both patterns allow us to swap out implementations.

It seems that I am not alone in getting confused in the disctintion between these two patterns. A simple google search with the phrase "bridge and adapter pattern" returns quite a few results. Here is an article in code project that illustrates the difference to a certain degree.

What came to mind in trying to determine the pattern required is the forces at work. This something that Steve Tockey pointed out when determining what pattern to use. He said basically that an engineer does not wake up one day and say "I think I will build a suspension bridge". The engineer must take into account the forces (tension, compression, bending, torsion, shear) that the bridge is most suitable for based on the architectural requirements. In other words he must take into account the physical requirements of the bridge.

Taking the forces into account, made me think about what exactly each of the two patterns was trying to solve. What is the problem that I am trying to solve? The bridge pattern is simply separating abstraction from implementation. This separation allows us to swap out different implementations at runtime. This is the basic premise of an interface or an abstract class. On the other hand, the adapter pattern is trying to adapt an interface to an implementation.

In the case of the bridge pattern this may be a simple case of different implementations. In other words two class that happen to implement the same interface. With the bridge pattern the programmer will usually have ownership of the interface definition as well as the concrete class.

In the case of the adapter pattern the programmer will usually not have ownership of the concrete class that it is adapting to. Additionally the programmer may have to do some conversion of data types, converting from more parameters to less parameters or vise versa. We are actually adapting one concrete class(this may be a class or a static call) to an abstraction.

Take the following code for exampe of an adapter for a graphics API. Although we are showing the GraphicsAPI code lets assume that we only have access to the binary assembly (DLL). This means that applying an interface to the Graphics API is out of the question. Furthermore, even if the code was available it would still not be feasible since the methods are static. Even in some cases where we might own the code it might not be feasible to modify the existing code since that would result in breaking existing code depends on it.

Now in our client code we can call the GraphicsAPI methods directly - this what most beginner coders would do. Later down the road in the maintenance of the code we might discover that we want to swap out the GraphicsAPI for some other API but since we made direct calls everywhere, we will have to change them to call the new API. If you are doing TDD you will come to this realizeation much earlier.

To avoid this problem altogether we can create an adapter to the API and use the adapter instead. This will enable us to later swap out the implementations or at least modify the code in one place where the API calls are made.

In the example I provide below I combine the bridge and adapter pattern to make the code more loosely coupled. Keep in mind that the bridge pattern does not require the adapter pattern, but in many cases the adapter pattern will need the bridge pattern. In my opinion the bridge pattern is the what the whole premise of inversion of control is built on. This is basically the concept that you can swap out implementations by using an abstraction.

As a disclaimer I will say that this explanation is by no means complete. As always, I encourage each of you to research and discover these patterns for yourself.

I have moved the code to the following location. My decision was mostly to the fact that blogger.com's code formatting is not up to par.

http://www.codepaste.net/nh1haj

Comments

Nolan Egly said…
I think you're watering the bridge down to a strategy pattern.

Strategy (and template) provide abstraction of an implementation. Bridge not only abstracts an implementation, but allows the abstraction and implementation to vary independently. This is especially useful to control cominatorial explosion.

For example, you might have a graphics API for a screen display, and another graphics API for a printer or plotter. We need to be able to change between GraphicsAPI and IMyDrawingApi without caring whether we're working with a plotter or a screen (avoid GraphicsAPI.DrawOnScreen() and GraphicsAPI.DrawOnPlotter().

Bridge provides this. It involves separating what was combined in a single concern into two different abstractions, each with multiple implementations. Strategy and template simply provide one abstraction over multiple implementations.
Fernando Zamora said…
Isn't that what IMyDrawingApi does? The IMyDrawingApi could be tied to a plotter or a printer. The client does not care. In this case I only demo'ed the implemention of an Adapter against one API. It could have other implementations (adapters). In other words the ClientWithBridgeAdapter would have other implementations. The _myDrawingAdapter would be adapted to either a plotter or a printer.

Take a look at the sample in wikipedia (http://en.wikipedia.org/wiki/Bridge_pattern). They use the same basic concept except that instead of an interface they use an abstract class.
Fernando Zamora said…
The drawingAdapter (which should be _myDrawingAdapter) within the ClientWithBridgeAdapter will allow the abstraction and implementation to vary independently.
Fernando Zamora said…
I think I see the point you are making Nolan. I think that I missed the point with the bridge. The bridge should be more like this


public class DrawingBridge
{
private IMyDrawingApi _myDrawingAdapter;

public DrawingBridge(IMyDrawingApi drawingAdapter)
{
_myDrawingAdapter = drawingAdapter;
}

public void DrawCircle(int centerX, centerY, int radius)
{
_myDrawingAdapter.DrawCircle(centerX, centerY, radius);
}

...Same for Rectangle

}
Nolan Egly said…
// Here's what we start with
public class Display {
void DrawPixel(int x, int y, int rgbColor);
}

/* Note we're already using strategy pattern to abstract drawing on screen */
public interface Drawing
{
void DrawLine(Point topLeft, Point topRight);
}

public class SlowAndQualityDrawing : Drawing {
void DrawLine(Point topLeft, Point bottomRight)
{ /* Use Display.DrawPixel to draw simple line */ }
}

public class FastAndDraftDrawing : Drawing {
void DrawLine(Point topLeft, Point bottomRight)
{ /* Use Display.DrawPixel to draw antialiased line */ }
}

/* Now, we need to support plotters in addition to screen displays. In order to avoid four drawing methods
(SlowAndQualityDisplay, SlowAndQualityPlotter, FastAndDraftDisplay, SlowAndQualityPlotter) we need to decouple the medium from the display quality. Now we have TWO abstractions - quality and the media being rendered on. Enter the bridge between media and drawing... */

public interface Media {
void MarkSpot(int x, int y, int rgbColor);
}

public class Display : Media {
void MarkSpot(int x, int y, int rgbColor) {
/* draw a pixel */ }
}
public class Plotter : Media {
void MarkSpot(int x, int y, int rgbColor) {
/* move plotter to spot, lower head to mark paper */ }
}

public class SlowAndQualityDrawing : Drawing {
void DrawLine(Point topLeft, Point topRight)
{ /* Use Media.MarkSpot to draw simple line */ }
}

public class FastAndDraftDrawing : Drawing
{
void DrawLine(Point topLeft, Point bottomRight)
{ /* Use Media.MarkSpot to draw antialiased line */ }
}

/* There is no standalone "bridge" object, rather the bridge is between the drawing implementations
and the media implementations. We've made a bridge by splitting out responsibility for an aspect
of drawing into a second abstraction. Now the Media and Drawing implementations can vary without
effecting each other. Note we still have only two drawing methods, instead of the four we'd end up
with if we didn't create the media-drawing bridge. */
Fernando Zamora said…
I think your example is valid. I think that the pattern that I described just happens to be a different implementation. Think of the Bridge as you SlowAndQualityDrawing. You could implement other implementations of Bridge if you wanted. I am not sure that I see much of a difference though. The example that I provided pretty much goes in line with everything that I am understanding about the bridge pattern to include the example on Wikipedia(http://en.wikipedia.org/wiki/Bridge_pattern).

Also I think that patterns can differ in implementation. As long as they are serving their purpose, then they have met their goal.
Nolan Egly said…
Also I think that patterns can differ in implementation. As long as they are serving their purpose, then they have met their goal.

I completely agree with you. I expanded the example simply to illustrate a more concrete sense (media and quality) of two differing concerns being bridged by separating them into two different abstractions.

One of the problems with patterns is struggling with slightly differing implementations being classified differently by different people. They're still very much worth studying and discussing though.

Popular posts from this blog

Simple Example of Using Pipes with C#

Remote Access to Your Home Desktop Using No-IP