DEV Community

Cover image for Design Patterns: Bridge
Tamerlan Gudabayev
Tamerlan Gudabayev

Posted on • Updated on

Design Patterns: Bridge

As the series goes on, the weirder the names get?

Bridge pattern?

We ain't literally constructing a bridge it's more of a metaphor.

Today you will learn:

  • Core concepts behind the bridge pattern
  • How to implement the bridge pattern
  • How to recognize opportunities the bridge pattern
  • The benefits and downsides of the bridge pattern

Definition

The bridge pattern states that you have to build an ASCII bridge between your modules, like this:

Just kidding!

In all seriousness, the bridge pattern advocates for the separation of abstraction and implementation.

But what do you mean by abstraction and implementation?

Well, to make things simpler let's go over an example.

Problem

Imagine your amazon in its early days.

Back when they only sold hardcover books.

Their classes might look something like this:

This most definitely works.

But it looks a bit iffy.

If we wanted to create a new book called ActionBook and want to publish it both as a printed book and as an audiobook.

We would be forced to create two new classes:

  • ActionPrintBook
  • ActionAudioBook

But what if we also want to publish a digital version of the book?

Once again, we will be forced to create a new ActionDigitalBook class.

In a nutshell for every new book, we have to create up to 3 additional classes for each version.

Also, if you want to do any changes to the book, you will have to do them in multiple places, hence breaking the DRY (Don't Repeat Yourself) principle.

Over time, this gets messy very fast.

But no worries, this is where the bridge pattern shines.

Solution

If we examine the classes closely, what's the difference between the audio book and the print book?

You will obviously say the content, the print book outputs a bunch of text, while the audio book outputs audio.

Our first step would be to decouple the content from the book classes.

Let's create a content provider interface:

interface IBookContentProvider {
    public String[] getContent();
} 

class AutobiographyBookContentProvider implements IBookContentProvider {

    public String[] getContent(){
        return ["I was a boy", "now I'm not a boy"];
    }
}

class AutobiographyAudioBook implements AudioBook {
        IBookContentProvider contentProvider;

        public AutobiographyAudioBook(IBookContentProvider contentProvider){
            self.contentProvider = contentProvider;
        }

        public void publish(){
            String[] content = self.contentProvider.getContent()

            System.out.println("Published Book: " + content)
        }
}
Enter fullscreen mode Exit fullscreen mode

Let's recap what we did over here:

  1. First, we created an IBookContentProvider interface, that declares the method getContent that will essentially get our content.
  2. Then we created our first content provider called AutobiographyBookContentProvider that implements our IBookContentProvider interface.
  3. Finally we connected our AutobiographyBookContentProvider to our AutobiographyAudioBook through the constructor.

Right, now if we ever wanted to create a new book, we would simply create a new book content provider and simply connect it to our book types (print, audiobook, digital, etc...)

This is the basic premise of the bridge pattern.

It advocates for composition over inheritance.

When to use this pattern?

  1. Use the bridge pattern, when you want to decouple a monolithic class that has several variants of some functionality. The bigger the class becomes, the more complicated it gets. It get's harder to make changes, and there's is a high possibility of things simply breaking out. This is where the bridge pattern comes, and divides this huge monolithic class into several class hierarchies. You can change code in each class hierarchy independently, hence making it much more easier and maintainable to work with.
  2. Use the bridge pattern, when you want to extend a class into several independent variants. The bridge pattern advocates to separate classes into hierarchies. You essentially create building blocks which all work together that you can mix and match.
  3. Use the Bridge if you need to be able to switch implementations at runtime. If you have implemented the bridge pattern, it's very easy to change implementations. You simply have to change the classes that your passing.

Benefits and Downsides

It's not all sunshine and rainbows, let's go over the benefits and downsides of the bridge pattern.

Benefits

  • You create platform independent classes and apps.
  • The client doesn't know the nitty gritty details, it only deals with abstractions.
  • You can introduce new abstractions and implementations independently.
  • You focus on the high level logic in abstraction, and details in implementations.

Downsides

  • The program becomes more complicated due to the addition of many different classes and interfaces.

Conclusion

The bridge pattern is one of the most useful design patterns, I'm sure you will find some use for it at both work and pet projects. I would like to end it with a question, have you ever used the bridge pattern? if so how was it? did you regret it?

Thanks for reading!

Further Readings

If you want to learn more about the design patterns, I would recommend Diving into Design Patterns. It explains all 23 design patterns found in the GoF book, in a fun and engaging manner.

Another book that I recommend is Heads First Design Patterns: A Brain-Friendly Guide, which has fun and easy-to-read explanations.

The Plug

Make sure to follow me on Twitter @tamerlan_dev

Also, check out my blog for more content like this:

https://softwareadventuring.com/

Discussion (0)