October 22, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Working With Design Patterns: Bridge

  • March 5, 2008
  • By Jeff Langr
  • Send Email »
  • More Articles »

The predominance of client code now can work with a Formatter reference. If you design your application carefully, you'll need only instantiate the concrete formatter types in one place.

Formatter formatter = new BookHtmlFormatter();
String text = formatter.print(book);

Simplifying Class Combinations

Now, suppose you also need to print movie information in a slightly different format on both the web and on receipts. In fact, you probably also want to print similar information for other media types in the library, such as audio tapes. Further, you may need to start printing onto different media in a different format, such as microfiche. These new requirements could require you to create an explosion of combinations: BookFicheFormatter, TapeHtmlFormatter, TapeFicheFormatter, and so on. Instead, the strength of the bridge pattern will help you keep some sanity in class organization.

The path to deriving an improved solution through use of the bridge pattern is recognizing two things. First, the code in BookHtmlFormatter and BookPrintFormatter violates the single responsibility principle. The print method combines formatting information with the data (and organization of such) to be formatted. Second, any new combined derivative (for example, TapeHtmlFormatter) will necessarily need to introduce redundancies with the existing implementation, something you really want to avoid.

By using the bridge pattern, you separate the two SRP-violating concerns into two separate hierarchies. A Printer hierarchy represents the client's abstract need to extract information and organize a printout. The need to format elements properly, depending on the output medium (HTML or printer), is abstracted into a separate Formatter hierarchy. See Figure 1 for the UML.

Listing 3 shows the code for the abstractions, derived by a number of simple refactorings against the current implementation. Note the introduction of a new class, Detail. The Detail class is a simple structure that holds onto a label and the corresponding value for that label.

Listing 3: Abstractions for the bridge.

public abstract class Printer {
   public String print(Formatter formatter) {
      return formatter.format(getHeader(), getDetails());
   }

   abstract protected Detail[] getDetails();
   abstract protected String getHeader();
}

public interface Formatter {
   String format(String header, Detail[] details);
}

public class Detail {
   private String label;
   private String value;

   public Detail(String label, String value) {
      this.label = label;
      this.value = value;
   }

   public String getLabel() {
      return label;
   }

   public String getValue() {
      return value;
   }

}

Th BookPrinter class (see Listing 4) is a derivative of the Printer abstract class. It fills in the holes in the template method print, defined in Printer, by supplying code for the getHeader and getDetails abstract methods. These methods take specific Book information and organize them for the report. The Printer method print simply delegates this captured information over to the Formatter object. Listings 5 and 6 provide the code for the two formatter implementations.

Listing 4: BookPrinter.

public class BookPrinter extends Printer {
   private Book book;

   public BookPrinter(Book book) {
      this.book = book;
   }

   protected String getHeader() {
      return book.getClassification();
   }

   protected Detail[] getDetails() {
      return new Detail[] {
         new Detail("Author", book.getAuthor()),
         new Detail("Title",  book.getTitle()),
         new Detail("Year",   book.getYear()) };
   }
}




Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel