Skip to content

The Bridge Design Pattern in Java

Posted on:September 8, 2022 at 01:13 PM

The world of software design patterns offers a rich set of tools to tackle complex programming challenges. One such pattern is the Bridge design pattern, a powerful tool especially when dealing with multiple inheritances in a system. In this article, we will explore the essence of the Bridge design pattern and demonstrate its application in Java.

Table of contents

Open Table of contents

Sections

The Need for Bridge Pattern

Imagine a scenario where a class requires components from different parts, leading to potential classes proliferating due to the multiple variations between the required objects. For instance, a class representing shapes and colors can yield numerous variations such as red circles, blue circles, red squares, and blue squares. This proliferation worsens exponentially as we add more colors or introduce new dimensions. This complexity can be overwhelming and difficult to manage.

To mitigate this, the Bridge pattern provides a solution. It involves separating the shape and color into different parts, thus avoiding the need for multiple inheritance from both shape and color. The Bridge pattern helps convert the inheritance into composition, allowing for more manageable and flexible code.

bridgeUML

A Simple Abstract Example

Let’s delve into a simple abstract example to illustrate the concept. We’ll consider an example where we have phone operating systems and applications, representing different dimensions. While this example is basic, it provides a clear understanding of how the Bridge pattern works.

We start by defining a PhoneOS interface that outlines the operations related to the operating system, including upload, download, and display.

public interface PhoneOS {
    void upload(String data);
    void download(String url);
    void display(String data);
}

Next, we implement two classes representing different operating systems: Android and iOS. These classes implement the PhoneOS interface.

public class Android implements PhoneOS {
    // Implementation for Android OS
    // ...
}

public class iOS implements PhoneOS {
    // Implementation for iOS
    // ...
}

We then introduce another dimension, the application (app), represented by an App interface. This interface defines the method runApp().

public interface App {
    void runApp();
}

To establish a bridge between the PhoneOS and the App, we create specific app implementations, such as Facebook and Instagram. These implementations include a reference to a PhoneOS instance, forming the bridge.

public class Facebook implements App {
    private PhoneOS os;

    public Facebook(PhoneOS os) {
        this.os = os;
    }

    @Override
    public void runApp() {
        // Implement Facebook app functionality using the phone OS
        os.upload("Facebook data upload");
        os.download("facebook.com");
        os.display("Facebook data");
    }
}

public class Instagram implements App {
    private PhoneOS os;

    public Instagram(PhoneOS os) {
        this.os = os;
    }

    @Override
    public void runApp() {
        // Implement Instagram app functionality using the phone OS
        System.out.println("Displaying cached Instagram data");
        os.upload("Instagram data upload");
        os.download("instagram.com");
        System.out.println("Displaying fresh Instagram data");
    }
}

Lastly, we create a client class to test the bridge pattern. The client can now create instances of apps like Facebook and Instagram on different phone operating systems like Android and iOS.

public class Client {
    public static void main(String[] args) {
        // Create instances of apps on different phone operating systems
        App facebookOniOS = new Facebook(new iOS());
        App instagramOnAndroid = new Instagram(new Android());

        // Run the apps
        facebookOniOS.runApp();
        instagramOnAndroid.runApp();
    }
}

Conclusion

The Bridge design pattern provides a powerful solution to handle complex hierarchies and multiple inheritances by converting them into composition. It promotes flexibility and maintainability in software systems, making them easier to extend and adapt. By understanding and applying the Bridge pattern appropriately, developers can architect systems that are robust, modular, and efficient.

Happy coding!