Home [Design Patterns] Bridge Pattern
Post
Cancel

[Design Patterns] Bridge Pattern

Definition

The bridge pattern intends to decouple an abstraction from its implementation so that the two can vary independently.

The bridge pattern is a bit like the adapter pattern, but the intention of using them is different:

Design patternIntention
Adapter patternWe use it to hide the layer of calling other libraries, so that if the library changes,
the error is constraint in a limited space.
Bridge patternWe use it to avoid the exponential growth in number of classes. (See scenario)

Scenario

When we have a webpage that wants to display media sources like albums and books in a large view, a medium view, or a small view, we will need $2\times3=6$ kinds of class to pair up all of them. As the views and media sources grow, the number of classes grows exponentially.

But here, we can decouple the sources from the views and combine them using the bridge pattern, so that only $2+3=5$ of classes is needed.

Class Diagram

Bridge Pattern Bridge Pattern

IView defines the display methods, and it can have multiple views (ex: LargeView returns html script for displaying in large view). The view class also holds media resource IResource*, so that it can get the content.

IResource is an interface that defines a group of methods for views to call. The methods are agnostic about when they will get called and what views are calling.

The subclasses of IResource (ArtistResource and BookResource) have the actual media source (Artist and Book). Media sources (Artist and Book) are two independent classes with different methods and attributes. ArtistResource and BookResource have different media resources, but they all must have Snippet and ImageUrl defined in IResource`. This follows the segregation principle, where a class only has methods for its purpose.

The bridge pattern enables different views ($m$) to pair up with different resources ($n$) and can have $m \times n$ of combinations. And this separates the platform-specific (IView) from the platform-independent (IResource).

Used Cases

  • When creating different views for different devices and different resources.
  • When coupling different sets of objects.

Implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// bridge.h
#ifndef __BRIDGE_H__
#define __BRIDGE_H__

#include <memory>

#include "media.h" // contains Artist class and Book class

class IResource {
public:
    virtual std::string Snippet() = 0;
    virtual std::string ImageUrl() = 0;
};

class ArtistResource : public IResource {
private:
    Artist artist_;

public:
    // Another way is to pass in artist's pointer
    ArtistResource(const std::string& name, const std::string& biograph) : artist_(name, biograph) {}
    std::string Snippet() override;
    std::string ImageUrl() override;
};

class IView {
protected:
    std::unique_ptr<IResource> resource_;

public:
    virtual void DisplayText() = 0;
    virtual void DisplayImage() = 0;
};

class LargeView : public IView {
public:
    LargeView(std::unique_ptr<IResource>&& resource);
    void DisplayText() override;
    void DisplayImage() override;
};

#endif  //__BRIDGE_H__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// bridge.cpp
#include "bridge.h"

#include <iostream>

std::string ArtistResource::Snippet() {
    std::string snippet = std::string("Name: ") + artist_.GetName() + std::string("\n");
    snippet += std::string("Bio : ") + artist_.GetBiograph() + std::string("\n");
    return snippet;
}

std::string ArtistResource::ImageUrl() {
    return std::string(artist_.GetMediaUrl());
}

LargeView::LargeView(std::unique_ptr<IResource>&& resource) {
    resource_ = std::move(resource);
}

void LargeView::DisplayText() {
    std::cout << "<p>" << resource_->Snippet() << "</p>" << std::endl;
}

void LargeView::DisplayImage() {
    std::cout << "<img src='" << resource_->ImageUrl() << ">" << std::endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

#include "bridge.h"

int main() {

    LargeView large_view = LargeView(std::make_unique<ArtistResource>("cindytsai", "born in 1997"));

    large_view.DisplayText();
    large_view.DisplayImage();

    return 0;
}

Reference

This post is licensed under CC BY 4.0 by the author.