February 27, 2021
Hot Topics:

Working With Design Patterns: Bridge

  • By Jeff Langr
  • Send Email »
  • More Articles »

Design patterns exist for some of the most simple, fundamental object-oriented concepts. "These aren't patterns, these are things I've always used just as a regular part of doing OO," you might argue. The bridge pattern falls into this category of a concept so fundamental to OO that it seems to be overkill to consider it a pattern. But, understanding the bridge pattern in its simplest form allows you to understand its value in more complex circumstances.

The Design Patterns book provides a simple summary for the bridge pattern: "Decouple an abstraction from its implementation so that the two can vary independently." To construct code using the bridge pattern in Java, you define an interface and classes that implement the interface. That's it! The interface provides a consistent abstraction with which clients can interact. The interface also isolates the client from any knowledge of the specific type of implementation and from any implementation details.

The collections class framework in the Java API provides several examples of use of the bridge pattern. Both the ArrayList and LinkedList concrete classes implement the List interface. The List interface provides common, abstract concepts, such as the abilities to add to a list and to ask for its size. The implementation details vary between ArrayList and LinkedList, mostly with respect to when memory is allocated for elements in the list.

Your application can take advantage of this common interface: Wherever you would have a reference variable of either ArrayList or LinkedList type, replace the variable's type with the List interface type:

public void find(List<Patron> patrons, Patron requested) {
   for (Patron patron: patrons)
      if (patron.equals(requested))
         return patron;
   return null;

The logic in the find method doesn't care if the list of patrons is implemented as an array or a linked list. This use of the bridge pattern improves the maintainability of your code. If all of your code is structured this way, you can change your code from using an ArrayList to a LinkedList, or vice versa, in one place.

If you do test-driven development (TDD), the bridge pattern is indispensible when it comes down to implementing mocks. If your test targets a class whose collaborator is giving you testing headaches, the bridge pattern can be of assistance. You extract an interface from the troublesome collaborator. You then can build a test double (aka a mock) for the collaborator. This test double is a class that implements the same interface and thus emulates, or mocks, the collaborator. Your unit test can inject the test double into the target, thus "fixing" the collaborator for purposes of testing. The test target is none the wiser!

Listing 1 shows two classes that represent another potential application of the bridge pattern. Each of BookHtmlFormatter and BookPrintFormatter provides a print method. The job of this method is to return a nicely formatted string for a book in a library system, with the formatting dependent upon whether the book information is going to be printed on a receipt or as part of a web page.

Listing 1: Simple implementations.

// BookHtmlFormatter.java
public class BookHtmlFormatter {
   public String print(Book book) {
      StringBuilder builder = new StringBuilder();
      builder.append(book.getClassification() + "<br />");
      builder.append("<td>" + book.getAuthor() + "</td>");
      builder.append("<td>" + book.getTitle()  + "</td>");
      builder.append("<td>" + book.getYear()   + "</td>");
      return builder.toString();

// BookPrintFormatter.java
import static util.StringUtil.*;

public class BookPrintFormatter {
   public String print(Book book) {
      StringBuilder builder = new StringBuilder();
      builder.append(book.getClassification() + EOL);
      builder.append("Author: " + book.getAuthor() + EOL);
      builder.append("Title:  " + book.getTitle()  + EOL);
      builder.append(book.getYear() + EOL);
      return builder.toString();


You can extract a common interface, and have each of the two formatter classes implement this interface (see Listing 2).

Listing 2: A simple bridge.

public interface Formatter {
   String print(Book book);

public class BookPrintFormatter implements Formatter {
   // ...

public class BookHtmlFormatter implements Formatter {
   // ...

Page 1 of 3

This article was originally published on March 5, 2008

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date