Structural - Bridge Pattern

It helps you build apps/systems where you mix-and-match features without creating a big mess

You love drawing, and you have different drawing tools: pencil, marker, and paintbrush.

You also have different surfaces to draw on: paper, canvas, and wall.

If you want to try every tool on every surface, you don’t pick just one! You want to be able to take any tool and use it on any surface.

  • You can draw on paper with a pencil.

  • You can paint on a canvas with a brush.

  • You can make art on a wall with a marker.

But you don’t need to get a special pencil just for paper, or a special brush for canvas. Instead, any tool can work with any surface.

That’s what Bridge pattern does: It lets you connect any drawing tool to any surface, without making a different class for every possible combination. You can easily add a new tool or a new surface, and everything still works together!

To sum up: Bridge pattern is like using your favorite art tools across all surfaces—mix and match, with less effort!

This pattern help in decoupling abstraction from implementation, so that they can vary independently.

This prefers composition over inheritance.

Low Level Design

bridge pattern

Implementation

public abstract class AbstractVehicle {
	Workshop workshop1;
	Workshop workshop2;

	AbstractVehicle(Workshop workshop1, Workshop workshop2) {
		this.workshop1 = workshop1;
		this.workshop2 = workshop2;
	}

	abstract void manufacture();
}
public interface Workshop {
	void work();
}
public class ProduceWorkshop implements Workshop {
	@Override
	public void work() {
		System.out.println("Production completed.");
	}
}
public class AssembleWorkshop implements Workshop {
	@Override
	public void work() {
		System.out.println("Assemble done");
	}
}
public class Car extends AbstractVehicle {

	Car(Workshop workshop1, Workshop workshop2) {
		super(workshop1, workshop2);
	}

	@Override
	void manufacture() {
		System.out.println("Car");
		workshop1.work();
		workshop2.work();
	}
}
public class Bike extends AbstractVehicle {
	Bike(Workshop workshop1, Workshop workshop2) {
		super(workshop1, workshop2);
	}

	@Override
	void manufacture() {
		System.out.println("Bike");
		workshop1.work();
		workshop2.work();
	}
}
public class Client {
	public static void main(String[] args) {
		AbstractVehicle car = new Car(new ProduceWorkshop(), new AssembleWorkshop());
		car.manufacture();

		AbstractVehicle bike = new Bike(new ProduceWorkshop(), new AssembleWorkshop());
		bike.manufacture();
	}
}

Without Bridge Design Pattern

But the above solution has a problem. If you want to change the Bus class, then you may end up changing ProduceBus and AssembleBus as well and if the change is workshop specific then you may need to change the Bike class as well.

Example in JDK

InputStream source = new FileInputStream("notes.txt");  // choose data source
InputStream input = new BufferedInputStream(source);     // choose behavior

int data;
while ((data = input.read()) != -1) {
    System.out.print((char) data);
}

Change the source

source = new ByteArrayInputStream("Hello".getBytes());
input = new BufferedInputStream(source);

No need to change logic

It cleanly separates what you do from where data comes from.

This is the most popular structural design pattern.

Last updated

Was this helpful?