When to use the Bridge pattern and how is it different from the Adapter pattern?
Asked Answered
D

13

173

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 Adapter pattern with a little dependency injection thrown into the mix? Does it really deserve its own pattern?

Dislimn answered 26/11, 2008 at 4:12 Comment(1)
The GoF book answers this question directly.Syncom
M
81

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.

Mclaughlin answered 26/11, 2008 at 4:40 Comment(1)
Bridge has nothing to do with Template or Strategy. Bridge is a structural pattern. Template and Strategy are behavioral patterns.Syncom
G
277

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
Garica answered 21/5, 2012 at 16:31 Comment(7)
Why would you do inheritance for colors?Caramel
@Caramel because Color is an interface and Blue, Red are concrete colorsBarmecidal
This is just a refactoring. Bridge pattern intent: "Decouple an abstraction from its implementation so that the two can vary independently." Where is the abstraction and where is the implementation here?Crawford
Is not Rectangle(Color) a more abstract one that the BlueRectangle thing?Garica
@Crawford , Abstraction is "Shape.color" of property ,therefore class Red and class Blue is implementation,and Color interface is bridge.Lightheaded
I read tens of unappropriate examples which simply misuses inheritance, i.e. something which naturally feels like 'has a' is presented as 'is a'. This is the best answer I have found. Bravo! Short, informative, outlined.Wareing
@Crawford you're puzzled just as i was. those examples are poor because they deal with properties (like color). Bridge pattern is about behaviorHuttan
M
246

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...

Meridional answered 26/11, 2008 at 4:44 Comment(2)
See also Anton Shchastnyi diagram below for a graphical illustration of this explanation.Chrysostom
I do not think a color is a good example for an implementation hierarchy, it is rather confusing. There is a good example of the Bridge pattern in "Design patterns" by the GoF, where implementation is platform dependent: IBM's PM, UNIX's X etc.Crawford
M
230

When:

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

Refactor to:

     A         N
  /     \     / \
Aa(N) Ab(N)  1   2
Methionine answered 23/2, 2012 at 2:27 Comment(5)
I think it's very pragmatic approach to patterns: 1) describe suboptimal straight-forward design 2) refactor design/code to better factored oneProcaine
Use maths concept to explain the Bridge design pattern. Very interested.Bakke
This is just a refactoring. Bridge pattern intent: "Decouple an abstraction from its implementation so that the two can vary independently." Where is the abstraction and where is the implementation here?Crawford
John puts it nicely in a blog post. Found it to be a good read for high level overview.Ochone
nice, do you have diagrams like this for other patterns?Violative
M
81

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.

Mclaughlin answered 26/11, 2008 at 4:40 Comment(1)
Bridge has nothing to do with Template or Strategy. Bridge is a structural pattern. Template and Strategy are behavioral patterns.Syncom
S
34

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.

Sheepdip answered 25/5, 2010 at 9:20 Comment(0)
M
30

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

Mallon answered 26/11, 2008 at 4:44 Comment(6)
Hey Bill. I don't understand why we necessarily use Bridge pattern in device drivers. I mean we can easily delegate implementation (of read, write, seek etc.) to the correct class via polymorphism right? Or with a Visitor perhaps? Why it's have to be Bridge? Thanks in advance.Ask
@zgulser, yes, you do use polymorphism. The Bridge pattern describes one kind of usage of subclasses to decouple implementation from abstraction.Mallon
You meant decoupling Shape implementation (ie. Rectangle) from let's day Color abstraction right? And I believe you're saying there're variety of ways to do it and Bridge is just one of them.Ask
Yes, subclassing has other uses. This particular way of using subclasses is what makes it the Bridge pattern.Mallon
And the decoupling I mean is from the abstract Shape interface to a concrete Rectangle implementation. So you can write code that needs an object of the "Shape" type, even though the concrete object is really some subclass of Shape.Mallon
It's important to point out that the Bridge pattern can be implemented different ways depending on the capability of the language / system. Any language that allows definition of a class must necessarily have a way to define the interface of that class. But not all languages allow interface definitions independent from classes. For those that do (C# for example) the Bridge pattern can be implemented directly using such interface definitions and skip at least one layer of subclassing and private-object instantiation in doing so.Electron
S
9

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.

Saxon answered 26/11, 2008 at 5:1 Comment(2)
If you use this pattern then the AImpl doesn't even need a header. I just put it inline in the implementation file for the A classStalkinghorse
Your implementor is private. I have a new question in regards to this, see #17681262Pishogue
M
7

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.

Milore answered 14/9, 2013 at 22:52 Comment(0)
H
6

You're working for an insurance company where you develop a workflow application that manages different kind of tasks: accounting, contract, claims. This is the abstraction. On the implementation side, you must be able to create tasks from different sources: email, fax, e-messaging.

You begin your design with these classes:

public class Task {...}
public class AccountingTask : Task {...}
public class ContractTask : Task {...}
public class ClaimTask : Task {...}

Now, since each sources must be handled in a specific way, you decide to specialize each task type:

public class EmailAccountingTask : AccountingTask {...}
public class FaxAccountingTask : AccountingTask {...}
public class EmessagingAccountingTask : AccountingTask {...}

public class EmailContractTask : ContractTask {...}
public class FaxContractTask : ContractTask {...}
public class EmessagingContractTask : ContractTask {...}

public class EmailClaimTask : ClaimTask {...}
public class FaxClaimTask : ClaimTask {...}
public class EmessagingClaimTask : ClaimTask {...}

You end up with 13 classes. Adding a task type or a source type becomes challenging. Using the bridge pattern produces something easier to maintain by decoupling the task (the abstraction) from the source (which is an implementation concern):

// Source
public class Source {
   public string GetSender();
   public string GetMessage();
   public string GetContractReference();
   (...)
}

public class EmailSource : Source {...}
public class FaxSource : Source {...}
public class EmessagingSource : Source {...}

// Task
public class Task {
   public Task(Source source);
   (...)
}
public class AccountingTask : Task {...}
public class ContractTask : Task {...}
public class ClaimTask : Task {...}

Adding a task type or a source is now much more easier.

Note: Most developers would not create the 13 classes hierarchy upfront to handle this problem. However, in real life, you might not know in advance the number of source and task types ; if you have only one source and two task types, you would probably not decouple Task from Source. Then, the overall complexity grows as new sources and task types are added. At some point, you will refactor and, most often, end up with a bridge-like solution.

Hofer answered 2/6, 2020 at 2:18 Comment(0)
R
3

The key difference between the Adapter and Bridge design patterns lies in their intents. From Design Patterns, chapter 4, section ‘Bridge’, paragraph ‘Related Patterns’ (Gamma et al. 1994):

The Adapter (139) pattern is geared toward making unrelated classes work together. It is usually applied to systems after they’re designed. Bridge, on the other hand, is used up-front in a design to let abstractions and implementations vary independently.

  1. The word ‘independently’ means that the Bridge design pattern applies in this situation because shapes and colours are independent:
             ------Shape-----                           Shape       Colour
            /                \              Bridge       / \         / \
       Circle                Square         ----->  Circle Square  Red Blue
        / \                   / \
RedCircle BlueCircle  RedSquare BlueSquare
  1. But it does not apply in this situation because colours depend on shapes:
             ------Shape-----
            /                \
       Circle                Square
        / \                   / \
RedCircle BlueCircle  RedSquare GreenSquare
  1. And it is useless in this situation because there are a single shape and a single colour:
Shape
  |
Circle
  |
RedCircle

Tabular representation of situation 1:

| Shape  | Colour |          | Shape  |  | Colour |
| ------ | ------ |          | ------ |  | ------ |
| circle | red    |  Bridge  | circle |  | red    |
| circle | blue   |  ----->  | square |  | blue   |
| square | red    |
| square | blue   |

Tabular representation of situation 2:

| Shape  | Colour |
| ------ | ------ |
| circle | red    |
| circle | blue   |
| square | red    |
| square | green  |

Tabular representation of situation 3:

| Shape  | Colour |
| ------ | ------ |
| circle | red    |

Thus the Bridge design pattern in object-oriented programming is equivalent to normalisation to projection–join normal form, denoted PJ/NF (Fagin 1979), in relational databases.

In situation 1, the relation schema R(Shape, Colour) has the multivalued dependencies ∅ ↠ {Shape} (independent shapes) and ∅ ↠ {Colour} (independent colours) which are not implied by the set of key dependencies {KEY({Shape, Colour})}, so it is not in PJ/NF. Its projections are in PJ/NF because R1(Shape) has the trivial functional dependency {Shape} → {Shape} which is implied by the set of key dependencies {KEY({Shape})} and R2(Colour) has the trivial functional dependency {Colour} → {Colour} which is implied by the set of key dependencies {KEY({Colour})}.

In situation 2, the relation schema R(Shape, Colour) has the trivial multivalued dependency {Shape} ↠ {Colour} which is implied by the set of key dependencies {KEY({Shape, Colour})}, so it is already in PJ/NF.

In situations 3, the relation schema R(Shape, Colour) has the functional dependencies ∅ → {Shape} (single shape) and ∅ → {Colour} (single colour) which are implied by the set of key dependencies {KEY({Shape, Colour}), KEY(∅)}, so it is already in PJ/NF.

Retinoscopy answered 29/4, 2022 at 22:33 Comment(0)
B
1

I’ll give you one new example for a bridge pattern if you get board of the same old Shape and Color example.

Let’s say you have different ways to make payments like Card payment and net banking. And there are different payment gateways like CITI bank and HSBC bank.

Then you can just add the payment gateway member to the payment modes. And at runtime pass this information to the payment mode object. And make the payment.

So for example it will make the Card payment on the CITI bank payment gateway.

Bartender answered 29/1, 2022 at 19:33 Comment(0)
A
0

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.

Absolutism answered 29/12, 2012 at 16:32 Comment(0)
K
-9
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);
}
}
}
Knobkerrie answered 25/12, 2017 at 5:54 Comment(2)
I downvoted because I feel this is a convoluted, poorly formatted answer.Tabriz
Totally agree, how can you post answers on this site without a minimal attention to code indentation and clearnessDuchy

© 2022 - 2024 — McMap. All rights reserved.