March 4, 2021
Hot Topics:

Working With Design Patterns: Mediator

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

Unless you've been living in Antarctica, you've encountered the self-checkout line at the grocery store. And, if you're reading this article, well, you're a geek like me, so you have no fear of self-checkout. You might imagine one of the simplest possible use cases for this process:

Purchase a Single Item Via Credit Card

  1. Customer scans one item
  2. Touch screen displays item barcode, description, price
  3. Customer selects "pay now"
  4. Touch screen offers selection of cash or credit card
  5. Customer selects credit card
  6. Touch screen says "complete transaction on pinpad device"
  7. Customer swipes card on pin pad
  8. Pin pad requests pin
  9. Customer enters pin
  10. System verifies credit card #, exp date
  11. System prints receipt
  12. Touch screen prints "please take your purchase"

No doubt there are dozens more use cases, involving accepting and dispensing cash and change, weighing items, looking up items, entering an item code for unscannable items, scanning a store loyalty card, user neglects to put item in bagging area, and so on. The simple use case and the few additional possible use cases I listed should suggest that there are a good number of devices and/or subsystems involved:

  • Scanner
  • Touch screen
  • Pin pad
  • Printer
  • Inventory
  • Produce scale
  • Change dispenser
  • Bagging area scale
  • Bill accepter
  • Bill dispenser

The first two lines alone of the use case require three subsystems: scanner, touch screen, and inventory. You might consider that many of these devices could send messages to each other to accomplish actions. For example, the touch screen system could send a message to the pin pad device when the customer selects "credit card payment." After the customer swipes a credit card, the pin pad device could send a message back to the touch screen system. There might be a similar exchange protocol between the bagging scale and the touch screen system.

Even if having devices talk to one another directly was the best design, however, it's not even feasible in this environment. The self-checkout lane is actually an amalgam of devices produced by different manufacturers. They don't know how to talk to each other because there's no standard protocol for these devices.

Enter the mediator, an object whose job is to unify by acting as a conduit for messages that need to go from device to device. The touch screen might be a candidate for mediator, but technically it's just another dumb device that the grocery chain purchases from a vendor. The self-checkout line system itself will need to appoint its own mediator.

To demonstrate the mediator pattern, I'll consider only those first two lines of the use case. Interfaces for the subsystems involved appear in Listing 1.

Listing 1: Subsystem interfaces.

// Scanner.java
public interface Scanner {
   void addScannerListener(ScannerListener listener);

// ScannerListener.java
public interface ScannerListener {
   public void scanned(String barcode);

// TouchScreenDisplay.java
public interface TouchScreenDisplay {
   void appendPurchasedItem(String text);

// Inventory.java
import java.math.*;

public interface Inventory {
   BigDecimal price(String barcode);
   String description(String barcode);

The Scanner interface represents a really simple system. The scanner implementation waits until a barcode passes across its beams; then, it sends the barcode off to a registered listener (ScannerListener), and goes back to waiting for another barcode.

The TouchScreenDisplay interface is one-half of the touch screen device, the half that allows information to appear on the monitor that the customer interacts with. For simplicity purposes, the interface as presented here constrains the display to only being able to show purchase records. (To fully support the self-checkout process, the interface would need many more methods, including the ability to support displaying a menu, a confirmation message, an error message, and so on. Another interface would be required to capture customer interactions with the touch screen: payNow(), selectPaymentMethod(), etc.)

The Inventory subsystem returns the price and description for a given barcode by looking it up in the store's database.

Here is the core of a test that verifies the first two use case lines:

   new SelfChecker(scanner, display, inventory);
   assertEquals(lastDisplayed, "12345 - Green Eggs - $2.95");

Paraphrased, this test says: create a SelfChecker object, passing in references to the scanner, display, and inventory. Then simulate scanning an item with a specific barcode (eggs). Finally, verify that the last thing displayed on the touch screen shows the details for eggs. The SelfChecker object will mediate all the required interactions among scanner, display, and inventory to accomplish this goal.

Page 1 of 2

This article was originally published on June 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