DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Unraveling Lombok's Code Design Pitfalls: Exploring Encapsulation Issues
  • Architecture and Code Design, Pt. 2: Polyglot Persistence Insights To Use Today and in the Upcoming Years
  • Double-Checked Locking Design Pattern in Java
  • Messaging Design Pattern (MDP) In Java

Trending

  • Beyond ChatGPT, AI Reasoning 2.0: Engineering AI Models With Human-Like Reasoning
  • Failure Handling Mechanisms in Microservices and Their Importance
  • Zero Trust for AWS NLBs: Why It Matters and How to Do It
  • Hybrid Cloud vs Multi-Cloud: Choosing the Right Strategy for AI Scalability and Security
  1. DZone
  2. Coding
  3. Java
  4. Using the Bridge Design Pattern in Java

Using the Bridge Design Pattern in Java

Want to learn more about design patterns in Java? Check out this post to learn more about how to use the bridge design pattern in this tutorial.

By 
Brijesh Saxena user avatar
Brijesh Saxena
DZone Core CORE ·
Aug. 27, 18 · Tutorial
Likes (19)
Comment
Save
Tweet
Share
48.9K Views

Join the DZone community and get the full member experience.

Join For Free

In continuation of my previous articles on design patterns, here I am with another very useful pattern — the bridge design pattern.

Bridge Design Pattern

  • The bridge design pattern is a structural pattern used to decouple an abstraction from its implementation so that the two can vary independently.

  • Bridge patterns decouple the abstract class and its implementation classes by providing a bridge structure between them.
  • This bridge uses encapsulation, aggregation, and inheritance to separate responsibilities into various classes.

  • The bridge pattern is useful when both the class and what it does vary, often because changes in the class can be made easily with minimal prior knowledge about the program. 

  • We can think of the class itself as an abstraction, what the class can do as the implementation, and the bridge pattern, itself, as two layers of abstraction.

  • The bridge pattern allows us to avoid compile-time binding between an abstraction and its implementation. This is so that an implementation can be selected at run-time.
  • In other words, by using the bridge pattern, we can configure an abstraction with an implementor object at run-time. 
  • The bridge design pattern is one of the 23 well-known GoF design patterns.
  • Let's take a look at an example to better understand it.

Suppose there is a company that manufactures various types of vehicles, like bikes, cars, and buses. There are frequent changes in the vehicle, as new models of bikes and cars can be introduced and have different processes to manufacture them. To indicate this, I am creating a dedicated method minWorkTime() for each of the concrete vehicles. and the method will have different values based on the implementor concrete classes. There can be other new vehicles, like a scooter or truck in future as well. 

All the vehicle has to do is use the WorkShop to produce, assemble, or quality check (test) its work using the  work() method for production.

Below is the code for the  Vehicle class:

package design.bridge;

import java.util.ArrayList;
import java.util.List;

public abstract class Vehicle {

        // assempbly line for the workshops
      protected List<WorkShop> workshops = new ArrayList<WorkShop>();

      public Vehicle() {
      super();
      }

      public boolean joinWorkshop(WorkShop workshop) {
      return workshops.add(workshop);
      }

      public abstract void manufacture();

      public abstract int minWorkTime();

}


Below is the code for the Bike class:

package design.bridge;

public class Bike extends Vehicle {

      @Override
      public void manufacture() {
            System.out.println("Manufactoring Bike...");
            workshops.stream().forEach(workshop -> workshop.work(this));
            System.out.println("Done.");
            System.out.println();
      }

      @Override
      public int minWorkTime() {
      return 5;
      }

}


Below is the code for Car class:

package design.bridge;

public class Car extends Vehicle {

      @Override
      public void manufacture() {
            System.out.println("Manufactoring Car");
            workshops.stream().forEach(workshop -> workshop.work(this));
            System.out.println("Done.");
            System.out.println();
      }

      @Override
      public int minWorkTime() {
      return 10;
      }

}


Below is the code for the Bus class:

package design.bridge;

public class Bus extends Vehicle {

    @Override
    public void manufacture() {
        System.out.println("Manufactoring Bus");
        workshops.stream().forEach(workshop -> workshop.work(this));
        System.out.println("Done.");
        System.out.println();
    }

    @Override
    public int minWorkTime() {
    return 20;
    }

}


After defining the types of vehicles, we are not implementing specifications classes, like ProduceBike, AssembleBike, ProduceCar , or  AssembleCar. All we have done is created an assembly line of the workshops in the Vehicle class and each vehicle will join the workshop to perform its manufacturing or repairing processes.

To achieve this, we have created the interface WorkShop, which will act as a bridge between types of vehicles and concrete workshops (implementors) to perform manufacturing work with the work() method.

Below is the code for the  WorkShop interface:

package design.bridge;

public abstract class WorkShop {

public abstract void work(Vehicle vehicle);

}


This workshop interface will act as a bridge between various types of vehicles and its manufacturing work (implementors).

Now, we need to create implementors of the Workshop to define various types of workshops required to perform the manufacturing work.

Below is the code for the ProduceWorkShop class:

package design.bridge;

import java.util.concurrent.TimeUnit;

public class ProduceWorkShop extends WorkShop {

    public ProduceWorkShop() {
    super();
    }

    @Override
    public void work(Vehicle vehicle) {
          System.out.print("Producing... ");
          long timeToTake = 300 * vehicle.minWorkTime();
          try {
          TimeUnit.MILLISECONDS.sleep(timeToTake); // Thread.sleep(timeToTake);
          } catch (InterruptedException exp) {
          // nothing to do for now.
          } 
          System.out.printf("(Time taken: %d millis), Done.\n", timeToTake);
    }

}


Below is the code for the AssembleWorkShop  class:

package design.bridge;

import java.util.concurrent.TimeUnit;

public class AssembleWorkShop extends WorkShop {

      public AssembleWorkShop() {
          super();
      }

      @Override
      public void work(Vehicle vehicle) {
          System.out.print("Assembling... ");
          long timeToTake = 200 * vehicle.minWorkTime();
          try {
          TimeUnit.MILLISECONDS.sleep(timeToTake); // Thread.sleep(timeToTake);
          } catch (InterruptedException exp) {
          // nothing to do for now.
          } 
          System.out.printf("(Time taken: %d millis), Done.\n", timeToTake);
      }

}


Below is the code for the PaintWorkShop class:

package design.bridge;

import java.util.concurrent.TimeUnit;

public class PaintWorkShop extends WorkShop {

    public PaintWorkShop() {
    super();
    }

    @Override
    public void work(Vehicle vehicle) {
          System.out.print("Painting... ");
          long timeToTake = 100 * vehicle.minWorkTime();
          try {
          TimeUnit.MILLISECONDS.sleep(timeToTake); // Thread.sleep(timeToTake);
          } catch (InterruptedException exp) {
          // nothing to do for now.
          } 
          System.out.printf("(Time taken: %d millis), Done.\n", timeToTake);
    }

}


Below is the code for the RepairWorkShop class:

package design.bridge;

import java.util.concurrent.TimeUnit;

public class RepairWorkShop extends WorkShop {

    public RepairWorkShop() {
    super();
    }

    @Override
    public void work(Vehicle vehicle) {
        System.out.print("Repairing... ");
        long timeToTake = 150 * vehicle.minWorkTime();
        try {
        TimeUnit.MILLISECONDS.sleep(timeToTake); // Thread.sleep(timeToTake);
        } catch (InterruptedException exp) {
        // nothing to do for now.
        } 
        System.out.printf("(Time taken: %d millis), Done.\n", timeToTake);
    }

}


Below is the code for the TestWorkShop class:

package design.bridge;

import java.util.concurrent.TimeUnit;

public class TestWorkShop extends WorkShop {

    public TestWorkShop() {
    super();
    }

    @Override
    public void work(Vehicle vehicle) {
          System.out.print("Testing... ");
          long timeToTake = 50 * vehicle.minWorkTime();
          try {
          TimeUnit.MILLISECONDS.sleep(timeToTake); // Thread.sleep(timeToTake);
          } catch (InterruptedException exp) {
          // nothing to do for now.
          } 
          System.out.printf("(Time taken: %d millis), Done.\n", timeToTake);
    }

}


To make this example a little more interesting, I am putting a timed-sleep for a few milliseconds to indicate that the workshop takes different times in the manufacturing of different types of vehicles. The interesting part of the code is the use of the bridge pattern types of vehicles (Bike, Car, and Bus) and its manufactring implementations ( ProduceWorkShop , AssemebleWorkShop , PaintWorkShop , and  TestWorkShop) are completely separate and independent via the workshop bridge interface.

Vehicles and workshops are connected via the WorkShop Bridge interface and are separate and independent of each other. We can freely change them and define new ones if required.

Now, let's take a look at the main program to execute and test the code for the bridge pattern:

package design.bridge;

public class Main {

    public static void main(String[] args) {
          Vehicle bike = new Bike();
          bike.joinWorkshop(new ProduceWorkShop());
          bike.joinWorkshop(new AssembleWorkShop());
          bike.joinWorkshop(new TestWorkShop());
          bike.manufacture();

          Vehicle car = new Car();
          car.joinWorkshop(new ProduceWorkShop());
          car.joinWorkshop(new AssembleWorkShop());
          car.joinWorkshop(new PaintWorkShop());
          car.joinWorkshop(new TestWorkShop());
          car.manufacture();

          Vehicle bus = new Bus();
          bus.joinWorkshop(new RepairWorkShop());
          bus.joinWorkshop(new AssembleWorkShop());
          bus.joinWorkshop(new TestWorkShop());
          bus.manufacture();
    }

}


Below is the output of the program:

Manufactoring Bike...
Producing... (Time taken: 1500 millis), Done.
Assembling... (Time taken: 1000 millis), Done.
Testing... (Time taken: 250 millis), Done.
Done.

Manufactoring Car
Producing... (Time taken: 3000 millis), Done.
Assembling... (Time taken: 2000 millis), Done.
Painting... (Time taken: 1000 millis), Done.
Testing... (Time taken: 500 millis), Done.
Done.

Manufactoring Bus
Repairing... (Time taken: 3000 millis), Done.
Assembling... (Time taken: 4000 millis), Done.
Testing... (Time taken: 1000 millis), Done.
Done.


Well, there you have it! I hope this example clears up some of the benefits and implementation details of the bridge design pattern.

Liked the article? Please don't forget to click that like button. Happy coding!

Need more articles on Design Patterns? Below are some of them I have shared with you.

  • Null Object Pattern in Java
  • Using the Adapter Design Pattern in Java

  • Using the Bridge Design Pattern in Java

  • Strategy vs. Factory Design Patterns in Java

  • Decorator Design Pattern in Java

  • How to Use Singleton Design Pattern in Java

  • Singleton Design Pattern: Making Singleton More Effective in Java

Some additional Articles:

  • Java Enums: How to Make Enums More Useful

  • Java Enums: How to Use Configurable Sorting Fields

Design Java (programming language) Bridge pattern

Opinions expressed by DZone contributors are their own.

Related

  • Unraveling Lombok's Code Design Pitfalls: Exploring Encapsulation Issues
  • Architecture and Code Design, Pt. 2: Polyglot Persistence Insights To Use Today and in the Upcoming Years
  • Double-Checked Locking Design Pattern in Java
  • Messaging Design Pattern (MDP) In Java

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!