Question

Has anyone ever used the Bridge Pattern in a real world application? If so, how did you use it? Is it me, or is it just the Adaptor Pattern with a little dependency injection thrown into the mix? Does it really deserve its own pattern?

Was it helpful?

Solution

A classic example of the Bridge pattern is used in the definition of shapes in an UI environment (see the Bridge pattern Wikipedia entry). The Bridge pattern is a composite of the Template and Strategy patterns.

It is a common view some aspects of the Adapter pattern in the Bridge pattern. However, to quote from this article:

At first sight, the Bridge pattern looks a lot like the Adapter pattern in that a class is used to convert one kind of interface to another. However, the intent of the Adapter pattern is to make one or more classes' interfaces look the same as that of a particular class. The Bridge pattern is designed to separate a class's interface from its implementation so you can vary or replace the implementation without changing the client code.

OTHER TIPS

There's a combination of Federico's and John's answers.

When:

                   ----Shape---
                  /            \
         Rectangle              Circle
        /         \            /      \
BlueRectangle  RedRectangle BlueCircle RedCircle

Refactor to:

          ----Shape---                        Color
         /            \                       /   \
Rectangle(Color)   Circle(Color)           Blue   Red

The Bridge pattern is an application of the old advice, "prefer composition over inheritance". It becomes handy when you must subclass different times in ways that are orthogonal with one another. Say you must implement a hierarchy of colored shapes. You wouldn't subclass Shape with Rectangle and Circle and then subclass Rectangle with RedRectangle, BlueRectangle and GreenRectangle and the same for Circle, would you? You would prefer to say that each Shape has a Color and to implement a hierarchy of colors, and that is the Bridge Pattern. Well, I wouldn't implement a "hierarchy of colors", but you get the idea...

When:

        A
     /     \
    Aa      Ab
   / \     /  \
 Aa1 Aa2  Ab1 Ab2

Refactor to:

     A         N
  /     \     / \
Aa(N) Ab(N)  1   2

Adapter and Bridge are certainly related, and the distinction is subtle. It's likely that some people who think they are using one of these patterns are actually using the other pattern.

The explanation I've seen is that Adapter is used when you're trying to unify the interfaces of some incompatible classes that already exist. The Adapter functions as a kind of translator to implementations that could be considered legacy.

Whereas the Bridge pattern is used for code that is more likely to be greenfield. You're designing the Bridge to provide an abstract interface for an implementation that needs to vary, but you also define the interface of those implementation classes.

Device drivers is an often-cited example of Bridge, but I'd say it's a Bridge if you're defining the interface spec for device vendors, but it's an Adapter if you're taking existing device drivers and making a wrapper-class to provide a unified interface.

So code-wise, the two patterns are very similar. Business-wise, they're different.

See also http://c2.com/cgi/wiki?BridgePattern

In my experience, Bridge is a quite often recurring pattern, because it's the solution whenever there are two orthogonal dimensions in the domain. E.g. shapes and drawing methods, behaviours and platforms, file formats and serializers and so forth.

And an advice: always think of design patterns from the conceptual perspective, not from the implementation perspective. From the right point of view, Bridge cannot be confused with Adapter, because they solve a different problem, and composition is superior to inheritance not because of the sake of itself, but because it allows to handle orthogonal concerns separately.

The intent of Bridge and Adapter is different and we need both patterns separately.

Bridge pattern:

  1. It is a structural pattern
  2. Abstraction and implementation are not bound at compile time
  3. Abstraction and implementation - both can vary without impact in client
  4. Uses composition over inheritance.

Use the Bridge pattern when:

  1. You want run-time binding of the implementation,
  2. You have a proliferation of classes resulting from a coupled interface and numerous implementations,
  3. You want to share an implementation among multiple objects,
  4. You need to map orthogonal class hierarchies.

@ John Sonmez answer clearly shows effectiveness of bridge pattern in reducing class hierarchy.

You can refer to below documentation link to get better insight into bridge pattern with code example

Adapter pattern:

  1. It allows two unrelated interfaces to work together through the different objects, possibly playing same role.
  2. It modifies original interface.

Key differences:

  1. Adapter makes things work after they're designed; Bridge makes them work before they are.
  2. Bridge is designed up-front to let the abstraction and the implementation vary independently. Adapter is retrofitted to make unrelated classes work together.
  3. The intent : Adapter allows two unrelated interfaces to work together. Bridge allows Abstraction and implementation to vary independently.

Related SE question with UML diagram and working code:

Difference between Bridge pattern and Adapter pattern

Useful articles:

sourcemaking bridge pattern article

sourcemaking adapter pattern article

journaldev bridge pattern article

EDIT:

Bridge Pattern real world example ( As per meta.stackoverflow.com suggestion, incorporated documentation site example in this post since documentation is going to sun-set)

Bridge pattern decouples abstraction from implementation so that both can vary independently. It has been achieved with composition rather than inheritance.

Bridge pattern UML from Wikipedia:

Bridge pattern UML from Wikipedia

You have four components in this pattern.

Abstraction: It defines an interface

RefinedAbstraction: It implements abstraction:

Implementor: It defines an interface for implementation

ConcreteImplementor: It implements Implementor interface.

The crux of Bridge pattern : Two orthogonal class hierarchies using composition (and no inheritance). The Abstraction hierarchy and Implementation hierarchy can vary independently. Implementation never refers Abstraction. Abstraction contains Implementation interface as a member (through composition). This composition reduces one more level of inheritance hierarchy.

Real word Use case:

Enable different vehicles to have both versions of manual and auto gear system.

Example code:

/* Implementor interface*/
interface Gear{
    void handleGear();
}

/* Concrete Implementor - 1 */
class ManualGear implements Gear{
    public void handleGear(){
        System.out.println("Manual gear");
    }
}
/* Concrete Implementor - 2 */
class AutoGear implements Gear{
    public void handleGear(){
        System.out.println("Auto gear");
    }
}
/* Abstraction (abstract class) */
abstract class Vehicle {
    Gear gear;
    public Vehicle(Gear gear){
        this.gear = gear;
    }
    abstract void addGear();
}
/* RefinedAbstraction - 1*/
class Car extends Vehicle{
    public Car(Gear gear){
        super(gear);
        // initialize various other Car components to make the car
    }
    public void addGear(){
        System.out.print("Car handles ");
        gear.handleGear();
    }
}
/* RefinedAbstraction - 2 */
class Truck extends Vehicle{
    public Truck(Gear gear){
        super(gear);
        // initialize various other Truck components to make the car
    }
    public void addGear(){
        System.out.print("Truck handles " );
        gear.handleGear();
    }
}
/* Client program */
public class BridgeDemo {    
    public static void main(String args[]){
        Gear gear = new ManualGear();
        Vehicle vehicle = new Car(gear);
        vehicle.addGear();

        gear = new AutoGear();
        vehicle = new Car(gear);
        vehicle.addGear();

        gear = new ManualGear();
        vehicle = new Truck(gear);
        vehicle.addGear();

        gear = new AutoGear();
        vehicle = new Truck(gear);
        vehicle.addGear();
    }
}

output:

Car handles Manual gear
Car handles Auto gear
Truck handles Manual gear
Truck handles Auto gear

Explanation:

  1. Vehicle is an abstraction.
  2. Car and Truck are two concrete implementations of Vehicle.
  3. Vehicle defines an abstract method : addGear().
  4. Gear is implementor interface
  5. ManualGear and AutoGear are two implementations of Gear
  6. Vehicle contains implementor interface rather than implementing the interface. Compositon of implementor interface is crux of this pattern : It allows abstraction and implementation to vary independently.
  7. Car and Truck define implementation ( redefined abstraction) for abstraction : addGear() : It contains Gear - Either Manual or Auto

Use case(s) for Bridge pattern:

  1. Abstraction and Implementation can change independent each other and they are not bound at compile time
  2. Map orthogonal hierarchies - One for Abstraction and one for Implementation.

I have used the bridge pattern at work. I program in C++, where it is often called the PIMPL idiom (pointer to implementation). It looks like this:

class A
{
public: 
  void foo()
  {
    pImpl->foo();
  }
private:
  Aimpl *pImpl;
};

class Aimpl
{
public:
  void foo();
  void bar();
};  

In this example class A contains the interface, and class Aimpl contains the implementation.

One use for this pattern is to expose only some of the public members of the implementation class, but not others. In the example only Aimpl::foo() can be called through the public interface of A, but not Aimpl::bar()

Another advantage is that you can define Aimpl in a separate header file that need not be included by the users of A. All you have to do is use a forward declaration of Aimpl before A is defined, and move the definitions of all the member functions referencing pImpl into the .cpp file. This gives you the ability to keep the Aimpl header private, and reduce the compile time.

To put shape example in code:

#include<iostream>
#include<string>
#include<cstdlib>

using namespace std;

class IColor
{
public:
    virtual string Color() = 0;
};

class RedColor: public IColor
{
public:
    string Color()
    {
        return "of Red Color";
    }
};

class BlueColor: public IColor
{
public:
    string Color()
    {
        return "of Blue Color";
    }
};


class IShape
{
public:
virtual string Draw() = 0;
};

class Circle: public IShape
{
        IColor* impl;
    public:
        Circle(IColor *obj):impl(obj){}
        string Draw()
        {
            return "Drawn a Circle "+ impl->Color();
        }
};

class Square: public IShape
{
        IColor* impl;
    public:
        Square(IColor *obj):impl(obj){}
        string Draw()
        {
        return "Drawn a Square "+ impl->Color();;
        }
};

int main()
{
IColor* red = new RedColor();
IColor* blue = new BlueColor();

IShape* sq = new Square(red);
IShape* cr = new Circle(blue);

cout<<"\n"<<sq->Draw();
cout<<"\n"<<cr->Draw();

delete red;
delete blue;
return 1;
}

The output is:

Drawn a Square of Red Color
Drawn a Circle of Blue Color

Note the ease with which new colors and shapes can be added to the system without leading to an explosion of subclasses due to permutations.

for me i think of it as a mechanism where you can swap interfaces. In the real world you might have a class that can use more then one interface, Bridge lets you swap.

Bridge design pattern we can easily understand helping of service and dao layer.

Dao layer -> create common interface for dao layer ->
public interface Dao<T>{
void save(T t);
}
public class AccountDao<Account> implement Dao<Account>{
public void save(Account){
}
}
public LoginDao<Login> implement Dao<Login>{
public void save(Login){
}
}
Service Layer ->
1) interface
public interface BasicService<T>{
    void save(T t);
}
concrete  implementation of service -
Account service -
public class AccountService<Account> implement BasicService<Account>{
 private Dao<Account> accountDao;
 public AccountService(AccountDao dao){
   this.accountDao=dao;
   }
public void save(Account){
   accountDao.save(Account);
 }
}
login service- 
public class LoginService<Login> implement BasicService<Login>{
 private Dao<Login> loginDao;
 public AccountService(LoginDao dao){
   this.loginDao=dao;
   }
public void save(Login){
   loginDao.save(login);
 }
}

public class BridgePattenDemo{
public static void main(String[] str){
BasicService<Account> aService=new AccountService(new AccountDao<Account>());
Account ac=new Account();
aService.save(ac);
}
}
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top