Click here to Skip to main content
15,881,204 members
Articles / Programming Languages / C#
Article

Refactoring To Patterns: Bridge and Adapter Pattern

Rate me:
Please Sign up or sign in to vote.
2.59/5 (14 votes)
7 Apr 20057 min read 71.7K   38   3
The adapter and bridge patterns offer us another way to make our code more flexible, and gives us another option for code design. Developers new to OO may have already found they have used a version of one of these patterns in their code before, or can find a myriad of uses immediately.

Image 1

Introduction

Developers in .NET sometimes come from scripting language environments that are not strong on Object Oriented Methodologies. OO methodologies like refactoring and using design patterns can be intimidating and the value for the developer is hard to see. What the developers new to the OO world, and even more seasoned developers need to understand is that good design is not beyond scope in any project. Good habits simply must be learned that will make the developer a better designer.

In that mind set, I am submitting the first of several "how to" real world examples, used in my professional life, on how to use patterns in a simple, easy to follow manner. Many of us have ended up either writing or working on in-line, scripting based code. Taking some ideologies from refactoring methodology, this is not necessarily a bad thing. Of course, when you are first writing an algorithm or a series of logic statements, it seems easier to start with if....then....else. But as you continue to expand this code to more complex forms, this model can quickly become unmanageable. This is where refactoring and design pattern methodology can play an important and useful part in simplifying, enhancing and making code more useable (and understandable) to those who practice good OO design.

This article details a real world example of how to use the bridge and adapter patterns to help you develop a method to allow decoupling of an abstraction class from its implementation class or to allow a change of implementation from an interface. This is generally used when you have a class that might change, but you don't want those changes to affect a number of clients.

Note: This article is for helping developers understand how to convert their inline code to patterns better not provide strict examples on patterns. There are more than enough strict pattern examples, but to facilitate developers and others out there who are not familiar with patterns, I have written this and other articles like this.

The adaptor and bridge patterns are very similar. The main difference between an adaptor and a bridge pattern, is that a bridge pattern serves to decouple an abstraction class from its implementation, and an adaptor pattern converts the interface between classes with less inheritance.

I have reworked this article, from the demand of my readers, to illustrate the differences between the adaptor and bridge patterns. We will start with the bridge pattern, and at the end of the article I will show the difference between the two.

Background

Using a bridge or an adapter pattern is a form of encapsulation, which allows a developer to better control the way a client code base deals with the implementation class structure.

How to use the code

We start this example with the class WorkerObject, which we see has one constructor and one method. If this object changes or we want to use another object in our client code instead of WorkerObject, we might have to re-write or re-compile a lot of that code. To decouple this object from the client would seem to make sense:

C#
public class WorkerObject
{            
    public WorkerObject()
    {
        
    }                    
    public virtual void DoWork()
    {
        Console.WriteLine("Working...");
    }
}
.....client code
WorkerObject obj = new WorkerObject();
obj.DoWork();

So, to solve this problem, we need to create a bridge or an adapter class that will allow a client to access methods on this object, but also make sure that the changes in this object will not break the client object's calls to the methods, even if we change the WorkerObject for another object. Here we see the Bridge class. This class can be called and the standard implementation of WorkerObject's method DoWork will be executed. The Bridge object is an example of the bridge pattern because of its access to its implementation object by inherited objects, and its inherited relationships.

Note: Notice the ImplementationObject accessor, that allows access to the implementation object. Using this accessor in inherited classes, we can change the WorkerObject to an inherited class, with different functionality, without affecting any client code, or changing the base WorkerObject class.

C#
class Bridge
{
    private WorkerObject _workerObject;
     public Bridge
    {
        ImplementationObject = new WorkerObject();
    }
    protected WorkerObject ImplementationObject
    {
        get{return _workerObject;}
        set{_workerObject = value;}
    }
    public virtual void DoWork()
    {
        ImplementationObject.DoWork();
    }
}

Now let's say we wanted to use a different object other than WorkerObject for our implementation class. We still want to provide a standard ImplementationObject accessor, so we create a class inherited from WorkerObject, named LoaferObject, which overrides the DoWork method, in effect changing the way the object functions. We set this object as the implementation object, giving new functionality, while still offering the same method access to the client:

C#
public class LoaferObject : WorkerObject
{
    public LoaferObject()
    {

    }
    public override void DoWork()
    {
        Console.WriteLine("Loafing...");
    }
}
class AlternateBridge : Bridge
{
    public AlternateBridge()
    {
        ImplementationObject = new LoaferObject();
    }
    public virtual void DoWork()
    {
        ImplementationObject.DoWork();
    }
}

Now let's say we did not want to use WorkerObject at all, but instead wanted to house some other functionality in the DoWork method, such as another object or different code. We can easily do this, just by inheriting from Bridge and changing the DoWork method's code in any way we like:

C#
class TotallyDifferntBridge : Bridge
{
    public TotallyDifferntBridge()
    {
        ImplementationObject = null;
    }

    public virtual void DoWork()
    {
        TotallyDifferentObject diffObj = new TotallyDifferentObject();

        diffObj.DoWork();
    }
}

Now let's see how this would affect the client code. Well we started with a single class WorkerObject, and a call to its method DoWork. To make the client code more flexible, and to get the proper object implementation for each client instance, we might call the Bridge object, or its inherited classes from a factory, which based on some state or parameter or client type gets the correct adapter object:

C#
//.....client code calls the factory
Bridge adapter = BridgeFactory.GetAdapter();
adapter.DoWork();

Another way of using the Bridge class to keep the client code flexible and not change the basic class functionality is to simply construct the class directly for each client instance it is needed, constructing different polymorphic inherited instances for different needs:

C#
//.....client code
Bridge adapter = new Bridge();
adapter.DoWork();
adapter = new AlternateBridge();
adapter.DoWork();
adapter = new TotallyDifferntBridge();
adapter.DoWork();

Now let's take a look at an alternative, less involved way to do the same kind of thing, with less need for inheritance, using the adaptor pattern. Here we see the Adaptor class. Notice that this class has no access to its implementation object, hence no need for inheritance. We can provide access to the Adaptor class to client code, but have no need to give different implementations of that class outwards. We might use the adaptor pattern if we foresaw changes to the implementation object that we did not want to be seen by the client, but had no immediate need to provide a range of different class types to encapsulate these changes. Also to be included in this consideration of pattern implementation is that the implementation class itself would not become another class altogether, where we might need to retain the old class' functionality. Basically we might use the adaptor pattern if changes to the implementation object could be accomplished without the need for backward compatibility, or polymorphic changes to the DoWork method:

C#
class Adaptor
{
    private WorkerObject _workerObject;
    public Adaptor
    {
        _workerObject = new WorkerObject();
    }
    public virtual void DoWork()
    {
        _workerObject.DoWork();
    }
}

Points of Interest

The adapter and bridge patterns offer us another way to make our code more flexible, and gives us another option for code design. Developers new to OO may have already found they have used a version of one of these patterns in their code before, or can find a myriad of uses immediately. Like many of the more commonly used patterns, these two patterns are useful in a wide variety of code situations.

This is the fifth installment in the series I am writing on real world design patterns. All examples and the bulk of this article are taken from my professional experience as an architect. The examples given are templates only, and the designer must keep in mind that they are the ones who must decide where different patterns, if any, may be best used in their code.

Deciding to perform a refactoring effort from existing code to a pattern must be weighed on the necessity and need of the code itself. Patterns are only design templates, helpers to accommodate better overall design. I must stress that making an effort to use patterns will strengthen your overall design ability, but like your basic coding skills, it is something that is to be learnt and cultivated.

If this or any other in this series on design patterns is helpful or you have questions or comments please e-mail me at chris.lasater@gmail.com.

History

This is the second revision and is the fifth installment in a series.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Christopher G. Lasater

I am also a published author, please check out my book:
ISBN: 1-59822-031-4
Title: Design Patterns
Author:Christopher G. Lasater
More from my web site
Amazon.com


Comments and Discussions

 
GeneralBridge Or Adaptor? But not both! Pin
Sicle11-Apr-05 13:09
Sicle11-Apr-05 13:09 
Generalthanks Pin
f27-Apr-05 6:50
f27-Apr-05 6:50 
GeneralRe: thanks Pin
Christopher G. Lasater7-Apr-05 8:30
Christopher G. Lasater7-Apr-05 8:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.