Post

Structural Design Patterns: Bridge Method

Purpose

The Bridge Pattern is used to separate an abstraction from its implementation. This means that you can change or modify the implementation of a class without affecting the abstraction, and vice versa. In simple terms, it “decouples” the interface from the actual working logic (implementation), allowing you to vary the implementation independently from the client.

Explanation

Imagine you have different types of vehicles (Car, Bike) and different types of engines (ElectricEngine, PetrolEngine). Without a bridge, you might create subclasses for every combination: ElectricCar, PetrolCar, ElectricBike, PetrolBike, which is not scalable.

The Bridge Pattern allows you to separate the Vehicle abstraction from the Engine implementation. It helps to solve this by splitting things into two separate groups:

  • Abstraction: This is the general idea or interface, and it keeps a link to the actual implementation.
  • Implementation: These are the concrete ways to do things.

Instead of using inheritance (which can get complicated and rigid), it uses composition — meaning the abstraction holds a reference to an implementation. This way, the two parts are connected but can change independently, making your code more flexible and easier to maintain.

Ruby Example: Vehical with Bridge Pattern

Scenario

  • Engine is the Implementor interface with a method start_engine.
  • ElectricEngine and PetrolEngine are ConcreteImplementors that provide different engine behaviors.
  • Vehicle is the Abstraction that contains a reference to an Engine.
  • Car and Bike are Refined Abstractions that extend Vehicle.
  • At runtime, you can mix and match Vehicle types and Engine implementations without creating numerous subclasses.

Step 1: Define the Implementor Interface

1
2
3
4
5
class Engine
  def start_engine
    raise NotImplementedError, 'This method should be overridden.'
  end
end

Step 2: Define the Concrete Implementors

1
2
3
4
5
6
7
8
9
10
11
class ElectricEngine < Engine
  def start_engine
    puts "Starting electric engine silently."
  end
end

class PetrolEngine < Engine
  def start_engine
    puts "Starting petrol engine with a roar."
  end
end

Step 3: Redefined Vehicle Abstractions

1
2
3
4
5
6
7
8
9
10
11
12
13
class Car < Vehicle
  def start
    print "Car: "
    super
  end
end

class Bike < Vehicle
  def start
    print "Bike: "
    super
  end
end

Put it all together

1
2
3
4
5
6
7
8
9
10
# Usage
electric_engine = ElectricEngine.new
petrol_engine = PetrolEngine.new

electric_car = Car.new(electric_engine)
petrol_bike = Bike.new(petrol_engine)

electric_car.start # Output: Car: Starting electric engine silently.

petrol_bike.start # Output: Bike: Starting petrol engine with a roar.

How it works?

  • The abstraction holds a reference to an implementor object.
  • The abstraction delegates the work to the implementor.
  • Implementors are interchangeable without changing the abstraction.

Why Use It?

  • When you want to avoid a permanent binding between an abstraction and its implementation.
  • When both the abstraction and implementation should be extendable by subclassing.
  • When you want to switch implementations at runtime.
  • When you want to hide implementation details from clients.

Happy Coding :)

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

Comments powered by Disqus.