Lesson 5
Implementing the Bridge Pattern in Kotlin
Bridge Pattern

Now, let's explore the Bridge Design Pattern! The Bridge pattern is a structural design pattern that decouples an abstraction from its implementation, allowing both to evolve independently. This pattern is particularly useful when you want to avoid a permanent binding between an abstraction and its concrete implementation.

What You Will Learn

In this lesson, you will:

  • Understand the Bridge pattern and its purpose.
  • Learn how to implement the Bridge pattern through a detailed example with multiple components.
  • See how the Bridge pattern helps in creating flexible and scalable systems.

Let's dive into the Bridge pattern through a practical example.

Implementing the Bridge Pattern

The goal of the Bridge pattern is to decouple the abstraction from its implementation, allowing both to evolve independently and provide greater flexibility and scalability.

We will be implementing this pattern with devices like Printer and Scanner, which will run on different operating systems like Windows and MacOS.

Step 1: Define the Abstraction Layer

First, let's define the OperatingSystem interface. This interface will declare the run method, which will be implemented by different operating systems.

Kotlin
1interface OperatingSystem { 2 fun run(device: String) 3}

In this interface, the run method takes a device name and performs an operation on it.

Step 2: Implement Concrete Implementations

Next, we need concrete classes that implement the OperatingSystem interface. These classes will perform specific operations based on the operating system.

Kotlin
1class WindowsOS : OperatingSystem { 2 override fun run(device: String) { 3 println("Running $device on Windows OS.") 4 } 5}
Kotlin
1class MacOS : OperatingSystem { 2 override fun run(device: String) { 3 println("Running $device on MacOS.") 4 } 5}

These classes implement the run method for Windows and MacOS, respectively.

Step 3: Create the Abstraction Class

Now, we create the abstract class Device, which will hold a reference to an OperatingSystem. The Device class will then define an abstract method start.

Kotlin
1abstract class Device(protected val os: OperatingSystem) { 2 abstract fun start() 3}

Here, the Device class uses Kotlin's primary constructor to set the operating system and has an abstract method start to be defined by subclasses.

Step 4: Implement Refined Abstractions

Finally, we create concrete classes for specific devices, which will extend the Device class and implement the start method.

Kotlin
1class Printer(os: OperatingSystem) : Device(os) { 2 override fun start() { 3 print("Printer: ") 4 os.run("Printer") 5 } 6}
Kotlin
1class Scanner(os: OperatingSystem) : Device(os) { 2 override fun start() { 3 print("Scanner: ") 4 os.run("Scanner") 5 } 6}

These classes implement the start method to run the device on the specified operating system.

Step 5: Example Usage

Now, let's bring everything together and test our implementation.

Kotlin
1fun main() { 2 // Running a Printer on Windows OS 3 val printerOnWindows = Printer(WindowsOS()) 4 printerOnWindows.start() // Outputs: Printer: Running Printer on Windows OS. 5 6 // Running a Scanner on MacOS 7 val scannerOnMac = Scanner(MacOS()) 8 scannerOnMac.start() // Outputs: Scanner: Running Scanner on MacOS. 9}

In the main function, we create instances of Printer and Scanner with different operating systems and start these devices.

Importance and Benefits

The Bridge pattern is crucial for several reasons:

  • Decoupling Abstraction from Implementation: It allows both the abstraction and the implementation to change independently without affecting each other.
  • Increased Flexibility: By treating the implementation and the abstraction as separate class hierarchies, the system becomes more flexible and easier to expand.
  • Reduced Complexity: This pattern helps manage complex systems by breaking down the class hierarchies and minimizing the connections between them.

Understanding and implementing the Bridge pattern enables you to design systems that are more flexible, scalable, and maintainable.

Ready to solidify your understanding with hands-on practice? Let's proceed to the practice section!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.