[Design Pattern] Structural Patterns - Bridge

ยท

3 min read

[Design Pattern] Structural Patterns - Bridge

๐Ÿ“Œ Bridge Pattern

The Bridge pattern is a structural design pattern that explains how to assemble objects and classes into larger structures while keeping the structure flexible and efficient.

Overview

The Bridge pattern separates the abstraction and implementation parts of a system into separate classes. It allows them to vary independently and provides a bridge between them. The abstraction represents the higher-level functionality, while the implementation represents the lower-level details.

Managing changes is much easier in modular code

The key idea behind the Bridge pattern is to decouple the abstraction and implementation, allowing them to evolve independently. By using interfaces or abstract classes, the Bridge pattern enables the implementation and abstraction to vary independently.

Participants

The key participants in the Bridge pattern are:

  • Abstraction: The highest-level class in the abstraction hierarchy. It contains a reference to an object of the Implementor class and uses it to invoke the implementation's methods.

  • RefinedAbstraction: A subclass of the Abstraction class that adds additional functionality or refines the behavior defined by the Abstraction class.

  • Implementor: The interface or abstract class that defines the methods to be implemented by the ConcreteImplementor classes.

  • ConcreteImplementor: The classes that implement the Implementor interface or extend the Implementor abstract class. They provide the specific implementation of the methods defined by the Implementor.


In the example diagram above:

  • Animal is the abstraction class that defines the high-level functionality.

  • Tiger and Bird are subclasses of Animal that refine the abstraction and provide specific functionality.

  • Hunting_Handler is the interface that represents the implementation part.

  • Hunting_Method1 and Hunting_Method2 are concrete implementations of Hunting_Handler that provide different hunting methods.

Implementor

interface Hunting_Handler {
  find_Quarry();

  detected_Quarry();

  attack();
}

class Hunting_Method1 implements Hunting_Handler {
  find_quarry() {
    console.log("finding in water");
  }

  detected_quarry() {
    console.log("found out fish");
  }

  attack() {
    console.log("catch it");
  }
}

class Hunting_Method2 implements Hunting_Handler {
  find_quarry() {
    console.log("finding on the land");
  }

  detected_quarry() {
    console.log("found deer");
  }

  attack() {
    console.log("bite it");
  }
}

Abstraction

class Animal {
  find_quarry() {
    this.find_quarry();
  }

  detected_quarry() {
    this.detected_quarry();
  }

  attack() {
    this.attack();
  }

  hunt() {
    this.find_quarry();
    this.detected_quarry();
    this.attack();
  }
}

class Tiger extends Animal {
    super();
}

class Bird extends Animal {
    super();
}

๐Ÿ“Œ Why do we use the Bridge pattern?

We use the Bridge pattern to separate the abstraction and implementation parts of a system and allow them to vary independently. This provides several benefits:

  • Decoupling: The Bridge pattern decouples the abstraction from its implementation, allowing them to change independently. This improves the flexibility and maintainability of the code.

  • Extensibility: By separating the abstraction and implementation, it becomes easier to add new abstractions or implementations without modifying existing code. This makes the system more extensible.

  • Reduced Complexity: The Bridge pattern simplifies the system's design by breaking it down into smaller, manageable components. It promotes a clear separation of concerns and helps avoid a tangled hierarchy of classes.

  • Runtime Binding: The Bridge pattern allows the implementation to be selected or changed at runtime. This provides flexibility and allows the system to adapt to different scenarios or requirements.

Overall, the Bridge pattern promotes a modular and flexible design that is easier to understand, extend, and maintain. It is particularly useful when there is a need to decouple abstractions from their implementations and when the system's components are expected to evolve independently.

ย