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

Working With Design Patterns: Mediator

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

Fleshing out the details that complete the test requires the use of test doubles (see Listing 2). A stub Scanner implementation simply holds onto the ScannerListener object passed to addScannerListener. A TouchScreenDisplay "spy" object captures the last String argument sent over to the appendPurchasedItem method. An Inventory mock object verifies the appropriate arguments, then returns a hard-coded value.

Listing 2: SelfCheckerTest.

import static org.junit.Assert.*;
import java.math.*;
import org.junit.*;

public class SelfCheckerTest {
   private ScannerListener scannerListener;
   private String lastDisplayed;
   private static final String EGGS_BARCODE = "12345";

   @Test
   public void singleItemSale() {
      Scanner scanner = new Scanner() {
         @Override
         public void addScannerListener(ScannerListener listener) {
            SelfCheckerTest.this.scannerListener = listener;
         }
      };

      TouchScreenDisplay display = new TouchScreenDisplay() {
         @Override
         public void appendPurchasedItem(String text) {
            SelfCheckerTest.this.lastDisplayed = text;
         }
      };

      Inventory inventory = new Inventory() {
         @Override
         public String description(String barcode) {
            assertTrue(barcode.equals(EGGS_BARCODE));
            return "Green Eggs";
         }

         @Override
         public BigDecimal price(String barcode) {
            assertTrue(barcode.equals(EGGS_BARCODE));
            return new BigDecimal("2.95");
         }
      };

      new SelfChecker(scanner, display, inventory);
      scannerListener.scanned(EGGS_BARCODE);
      assertEquals(lastDisplayed, "12345 - Green Eggs - $2.95");
   }
}

In the middle of scanner, display, and inventory subsystems lies the SelfChecker object—the mediator (see Listing 3). The SelfChecker sends a message to the scanner to add itself as a ScannerListener. Upon receiving a scanned message, the SelfChecker obtains description and price information for a barcode by sending a message to the Inventory object, and finally sends a message to the touch screen display, passing the appropriate output string.

Listing 3: SelfChecker.

public class SelfChecker implements ScannerListener {
   private final TouchScreenDisplay display;
   private final Inventory inventory;

   public SelfChecker(Scanner scanner, TouchScreenDisplay display,
                      Inventory inventory) {
      this.display = display;
      this.inventory = inventory;
      scanner.addScannerListener(this);
   }

   @Override
   public void scanned(String barcode) {
      String purchase =
         String.format("%s - %s - $%s",
               barcode,
               inventory.description(barcode),
               inventory.price(barcode));
      display.appendPurchasedItem(purchase);
   }
}

In lieu of the mediator pattern, a different solution might involve creating classes that adapt each of the devices in the self-checker system. Imagine the entanglement among objects of these adapter types as they sent messages to each other. Most adapter classes would have dependencies on most other classes, promoting all the negatives of a highly-coupled system. Ultimately, all the messages flying about would make the code considerably more confusing and costly to maintain.

Figure 1: Mediator.

About the Author

Jeff Langr is a veteran software developer with over a quarter century of professional software development experience. He's written two books, including Agile Java: Crafting Code With Test-Driven Development (Prentice Hall) in 2005. Jeff has contributed a couple chapters to Uncle Bob Martin's upcoming book, Clean Code. Jeff has written over 75 articles on software development, with over thirty appearing at Developer.com. You can find out more about Jeff at his site, http://langrsoft.com, or you can contact him via email at jeff at langrsoft dot com.





Page 2 of 2



Comment and Contribute

 


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

 

 


Sitemap | Contact Us

Rocket Fuel