CodeZine(コードジン)

特集ページ一覧

デザインパターンの使い方: Mediator

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/12/15 14:00

目次

 こちらが、ユースケースの最初の2項目分を確認するテストのコア部分です。

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

 このテストでは、まず、スキャナ、ディスプレイ、商品情報への照会を行うSelfCheckerオブジェクトを作成します。次に、バーコードの付いた商品(玉子)1点を擬似的にスキャンします。最後に、タッチパネルに表示された最新の内容が、玉子に関する詳細であることを確認します。SelfCheckerオブジェクトは、スキャナ、ディスプレイ、商品情報の間で必要な全てのやり取りの仲介を行います。

 十分なテストを実施するには、テスト用の「代役」を立てる必要があります(リスト2を参照)。スタブ実装のScannerは、addScannerListenerに渡されるScannerListenerオブジェクトを保持しているだけです。「スパイ」オブジェクトであるTouchScreenDisplayは、appendPurchasedItemメソッドに渡される最新のString引数を取得します。Inventoryの模擬オブジェクトは、引数の正当性を確認して、コード内に記述された値を返します。

リスト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");
   }
}

 スキャナ、ディスプレイ、商品情報サブシステムの内部には、メディエータであるSelfCheckerオブジェクトが存在します(リスト3を参照)。SelfCheckerはスキャナにメッセージを送信し、自身をScannerListenerとして追加します。scannedのメッセージを受け取ると、SelfCheckerInventoryオブジェクトにメッセージを送信することで、直ちにバーコードに対応する商品情報と価格情報を取得し、最終的にタッチパネルのディスプレイにメッセージを送信して、適切な出力文字列を渡します。

リスト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);
   }
}

 Mediatorパターンを使わない別のソリューションとして、セルフレジシステムの各デバイスの「変換アダプタ」として機能するクラスを作成する、という方法も考えられます。しかし、このようなアダプタオブジェクトが互いにメッセージを送信するときの煩雑さを想像してみてください。ほとんどのアダプタクラスは他のさまざまなクラスと依存関係を持つことになり、結合度の高いシステムのあらゆるマイナス面が噴出してくるでしょう。結局は、クラス間で飛び交うメッセージのせいで、コードがより複雑となり、保守に費用がかかるものになるのではないでしょうか。

図1 Mediatorパターン
図1 Mediatorパターン


  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:デザインパターンの使い方

もっと読む

著者プロフィール

  • japan.internet.com(ジャパンインターネットコム)

    japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.com や EarthWeb.c...

  • Jeff Langr(Jeff Langr)

    本格的なソフトウェアの開発に四半世紀以上携わってきたベテランのソフトウェア開発者。『Agile Java: Crafting Code With Test-Driven Development』(Prentice Hall、2005年)と、他の1冊の著書がある。『Clean Code』(Uncle...

あなたにオススメ

All contents copyright © 2005-2022 Shoeisha Co., Ltd. All rights reserved. ver.1.5