Design Pattern: Bridge Pattern

Summary

Pattern NameBridge Pattern
Pattern TypeStructural Pattern
Other NamesHandle/Body
ScopeObject
TaglineDecouple abstraction from implementation to enable independent working
Use casesWhen we want the abstraction and implementation
to work separately/independently
Related PatternsAbstract Factory
Adapter
Difficulty LevelMedium
Implementations

Definition

Say, we are printing some UI Elements for an application (for Desktop / Web / Mobile).

We have UI element base class and actual element classes like Button, Input field, Table, Text, TextArea, etc. Whenever we need to print an element we use these element classes.

On the other hand, we have classes for setting colors, like Red, Green, Blue, etc.

While printing the element we want to select any element dynamically as required and at the same time we want to set the color dynamically. So that each element and color can be set and changed dynamically.

To handle this case, we can use the Bridge pattern. Using Bridge we can decouple the implementation of UI Element and Color Schema, so the elements and colors will have a separate hierarchy. That way the implementation of the Elements and Color will be independent and the element color can be set dynamically.

Birdge pattern decouples an abstraction from its implementation, so that those can be changed independently.

Use Cases

Here are a few use cases of bridge pattern.

  • When we want to eliminate strong binding between abstraction and implementation.
  • When we want the implementation to be switched at runtime.
  • When we want to combine and/or extend different attractions and implementations independently.
  • When we want the change in the implementation, not to impact the client.
  • When we want to hide the implementation from the client.

Implementation

To understand the implementation we have to first understand 4 terms, which are the primary elements of Bridge pattern implementation.

  1. Implementor: Interface that represents some criteria of the actual abstraction.
  2. Concrete Implementor: Implementation class of the implementor interface.
  3. Abstraction: Abstract class that represents the object we want to use in the client.
  4. Refined Abstraction: Implementation classes of the Abstraction.

Check the following diagram for the use-cases of these 4 elements.

Follow the steps below to implement Bridge pattern.

  1. Create an interface for representing the implementor.
  2. Create one or more classes (as required) and implement the implementor interface for these classes. These classes will represent some criteria of the actual object that we want to use.
  3. Create an Abstract class to represent the actual objects that we want to use.
  4. Store a reference of the implementor class in the abstraction, so that the implementor can be used in different places of abstraction. Pass the implementor object in the constructor and save the reference.
  5. Create classes and extend the Abstract class. Use functions from the implementor in these classes.
  6. From the client create an object of the Abstraction class, and pass an object of the implementor classes to the abstraction.

This way the Implementor and the Abstraction will be completely separate.

Examples

Let’s take a look at some examples that demonstrate Bridge pattern implementation.

Example #1: UI Element Color

interface ColorSchema

    void setColor()

end interface

class Red implements ColorSchema
    
    function setColor()
        print "Setting proper color for Red color schema"
    end function

end class

class Green implements ColorSchema 

    function setColor()
        print "Setting proper color for Green color schema"
    end function

end class

class Blue implements ColorSchema 

    function setColor()
        print "Setting proper color for Blue color schema"
    end function

end class
abstract class UIElement

    var colorSchema: ColorSchema

    constructor(ColorSchema colorSchemaParam)
       colorSchema = colorSchemaParam
    end constructor

   abstract function printElement()

end class

class Button extends UIElement

    constructor(ColorSchema colorSchemaParam)
        // Call parent constructor
        super(colorSchemaParam)
    end constructor

    function printElement()
        // Write code for printing element
        print "Printing Button"

        // Set color schema
        colorSchema.setColor()
    end function

end class

class Input extends UIElement

    constructor(ColorSchema colorSchemaParam)
        // Call parent constructor
        super(colorSchemaParam)
    end constructor

    function printElement()
        // Write code for printing element
        print "Printing Input"

        // Set color schema
        colorSchema.setColor()
    end function

end class

class Table extends UIElement

    constructor(ColorSchema colorSchemaParam)
        // Call parent constructor
        super(colorSchemaParam)
    end constructor

   function printElement()
        // Write code for printing table element
        print "Printing Table"

        // Set color schema
        colorSchema.setColor()
    end function

end class

Demo

// Print a Red table
table: UIElement = new Table(new Red())
table.printElement()

// Print a Green Input box
input: UIElement = new Input(new Green())
input.printElement()

// Print a Blue Button
button: UIElement = new Button(new Blue())
button.printElement()

// Print a Red Button
button2: UIElement = new Button(new Red())
button2.printElement()

Output

Printing Table
Setting proper color for Red color schema

------------------------------

Printing Input
Setting proper color for Green color schema

------------------------------

Printing Button
Setting proper color for Blue color schema

------------------------------

Printing Button
Setting proper color for Red color schema

Example #2: Transport Seat Reservation

interface Seat

    void selectSeat()

end interface


class BusinessClassSeat implements Seat 
    
    function selectSeat()
        print "Select an Business class seat"
    end function

end class

class EconomyClassSeat implements Seat
    
    function selectSeat()
        print "Select an Economy class seat"
    end function

end class
abstract class Transport

    var seat: Seat

    constructor(Seat seatParam)
       seat = seatParam
    end constructor

   abstract function selectTransport()

end class

class Plane extends Transport

    constructor(Seat seatParam)
        // Call parent constructor
        super(seatParam)
    end constructor

    function selectTransport()
        // Write code to select transport
        print "Plane selected for transport"

        // Select seat
        seat.selectSeat()
    end function

end class

class Train extends Transport

    constructor(Seat seatParam)
        // Call parent constructor
        super(seatParam)
    end constructor

    function selectTransport()
        // Write code to select transport
        print "Train selected for transport"

        // Select seat
        seat.selectSeat()
    end function

end class

Demo

Transport plane = new Plane(new BusinessClassSeat())
plane.selectTransport()

Transport plane2 = new Plane(new EconomyClassSeat())
plane2.selectTransport()

Transport train = new Train(new EconomyClassSeat())
train.selectTransport()

Output

Plane selected for transport
Select an Business class seat

------------------------------

Plane selected for transport
Select an Economy class seat

------------------------------

Train selected for transport
Select an Economy class seat

Code Implementations

Use the following links to check Bridge pattern implementation in specific programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.