Java design patterns: Bridge

Today we will take a look at another Java design pattern from the structural patterns category – Bridge. Design patterns in this category deal with class structure such as inheritance and composition.

Read more – a series of design patterns:

The Bridge design pattern is a design pattern used in software engineering to separate the abstraction from the implementation so that the two parts can change independently of each other. In doing so, the Bridge pattern uses encapsulation, aggregation, and can use inheritance to divide responsibilities into different classes.

What problem does the Bridge design pattern solve?

The Bridge pattern solves the problem when we want a class hierarchy to have two independent dimensions of extensibility-one for abstraction and one for implementation.

The main goal of the Bridge pattern is to allow clients to select and combine different implementations with different abstractions without changing their class hierarchy. This way we can achieve more flexibility and reusability in the code.

Thus, using the Bridge design pattern allows us to have the abstraction and its implementation defined and extended independently of each other. In addition, it will also allow us to avoid the coupling between the abstraction and its implementation at compile time, so that the implementation can then be selected at runtime.

Example of Bridge implementation in Java

Now we will show how to implement the Bridge design pattern in Java. In this example, we will program the ability to shop in different types of stores (e.g. online store, brick-and-mortar store), using different payment methods (e.g. credit card, PayPal). For abstraction we use the abstract class Obchod and for different payment implementations we use the interface SposobPlatby.

We separate the Abstraction from its Implementation by placing them in separate class hierarchies. We then implement the Abstraction by delegating to the Implementor object.

Abstraction Obchod represents different types of shops (e.g. brick-and-mortar shop, online shop).

Obchod.java

package designpatterns;

// Abstrakcia - typ obchodu
abstract public class Obchod {
    protected SposobPlatby sposobPlatby;

    public Obchod(SposobPlatby sposobPlatby) {
        this.sposobPlatby = sposobPlatby;
    }

    public abstract void nakup(float suma);
}

The more specific abstractions(KamennyObchod and InternetovyObchod) represent different types of shops that can make purchases and use SposobPlatby to process payments.

KamennyObchod.java

package designpatterns;

// Konkrétnejšia abstrakcia obchodu - kamenný obchod
public class KamennyObchod extends Obchod {
    public KamennyObchod(SposobPlatby sposobPlatby) {
        super(sposobPlatby);
    }

    public void nakup(float suma) {
        System.out.println("Nákup v kamennom obchode.");
        sposobPlatby.spracujPlatbu(suma);
    }
}

InternetovyObchod.java

package designpatterns;

// Konkrétnejšia abstrakcia obchodu - internetový obchod
public class InternetovyObchod extends Obchod {
    public InternetovyObchod(SposobPlatby sposobPlatby) {
        super(sposobPlatby);
    }

    public void nakup(float suma) {
        System.out.println("Nákup v internetovom obchode.");
        sposobPlatby.spracujPlatbu(suma);
    }
}

The SposobPlatby implementer represents different payment methods (e.g. credit card, PayPal).

SposobPlatby.java

package designpatterns;

// Implementátor - rozhranie pre spôsob platby
public interface SposobPlatby {
    void spracujPlatbu(float suma);
}

Specific implementations (PlatbaKreditnouKartou and PlatbaPayPal) provide specific implementations of payment methods.

PlatbaKreditnouKartou.java

package designpatterns;

// Konkrétna implementácia – platba kreditnou kartou
public class PlatbaKreditnouKartou implements SposobPlatby {
    private String cisloKarty;

    public PlatbaKreditnouKartou(String cisloKarty) {
        this.cisloKarty = cisloKarty;
    }

    public void spracujPlatbu(float suma) {
        System.out.println("Spracováva sa platba kreditnou kartou vo výške " + suma + "€ s číslom karty " + cisloKarty  + ".");
    }
}

In the Main class, we create instances of different types of stores with different payment methods and make purchases. The Bridge pattern allows us to change and combine payment methods and deal types without changing the hierarchy of the Deal class.

Main.java

import designpatterns.*;

public class Main {
    public static void main(String[] args) {
        SposobPlatby platbaKreditnouKartou = new PlatbaKreditnouKartou("1234-5678-9012-3456");
        SposobPlatby platbaPayPal = new PlatbaPayPal("mojpaypal@email.com");

        Obchod internetovyObchod = new InternetovyObchod(platbaKreditnouKartou);
        Obchod kamennyObchod = new KamennyObchod(platbaPayPal);

        internetovyObchod.nakup(100.0f);
        kamennyObchod.nakup(50.0f);
    }
}

The output of this example is:

java output from the example bridge design pattern
Bridge design pattern – example output

Summary

The Bridge design pattern is used in a situation where we need to separate abstraction from implementation so that we can change them independently.

We have prepared the files with the above example in the form of code that you can run directly in Java. Download the Java Bridge code here.

Do you know the Java programming language? If you are looking for a job, for example. as a Java developer, see our company benefits and respond to the latest job offers.

About the author

Jozef Wagner

Java Developer Senior

I have been programming in Java for more than 10 years, currently I am working in msg life Slovakia as a senior Java programmer and I help customers to implement their requirements into Life Factory insurance software. In my free time I like to relax in the mountains or play a good computer game.

Let us know about you