Mediatorパターンの例
ずっと南極大陸に暮らしているという人でもない限り、スーパーに行ってセルフレジに出くわした経験が1回くらいあるのではないでしょうか。それに、この記事を読んでいるということは、皆さんも私のようなギークで、セルフレジでの精算を恐れてはいないと思います。
セルフレジでの一連の流れは、次のような最もシンプルなユースケースを思い浮かべるかもしれません。
商品1点のクレジットカードでの購入
- 顧客は商品1点をスキャンする。
- タッチパネルに商品のバーコード、商品情報、価格が表示される。
- 顧客は「支払い」を選択する。
- タッチパネルに現金またはクレジットカードの選択肢が表示される。
- 顧客はクレジットカードを選択する。
- タッチパネルに「ピンパッドでトランザクションを完了させてください」と表示される。
- 顧客はカードをピンパッドに通す。
- ピンパッドが暗証番号の入力を要求する。
- 顧客は暗証番号を入力する。
- システムはクレジットカードの番号と有効期限を確認する。
- システムはレシートを印字する。
- タッチパネルに「お買い上げの品物をお持ち帰りください」と表示される。
他にも、代金と釣り銭の受け渡し、商品の重量測定、商品の検索、スキャンできない商品に対する商品コードの入力、店舗のお客様カードのスキャン、ユーザーが商品を袋詰めエリアに入れ忘れる場合など、数多くのユースケースがあるのは間違いありません。ここで挙げたシンプルなユースケースや、いくつか考えられる補足的なユースケースから分かるように、このシナリオには次のような数多くのデバイスやサブシステムが登場します。
- スキャナ
- タッチパネル
- ピンパッド
- プリンタ
- 商品情報
- 商品の重量計
- 釣り銭支払機
- 袋詰めエリアの重量計
- 紙幣入金機
- 紙幣支払機
上に述べたユースケースの最初の2項目だけで、スキャナ、タッチパネル、商品情報の、3つのサブシステムが必要です。皆さんはこうしたデバイスの多くが、互いにメッセージを送信できると考えるかもしれません。例えば、顧客が「クレジットカード払い」を選択した場合には、タッチパネルシステムがピンパッドにメッセージを送り、顧客がクレジットカードをピンパッドに通すと、ピンパッドがタッチパネルシステムにメッセージを戻すという具合です。袋詰めエリアの重量計とタッチパネルシステムの間にも、おそらく同じような交換の手続きがあるのだろうと考えるのではないでしょうか。
しかし、そうではありません。たとえデバイス同士で直接やり取りさせることが最良のデザインだとしても、この環境でそれを実現するのは不可能です。セルフレジでは実にさまざまなメーカーのデバイスが混在しています。こうしたデバイスに標準のプロトコルはないので、デバイスは互いにどうやり取りするか関知していません。
ここで必要になるのがメディエータ(mediator、仲介者)です。これはつまり、デバイス間でメッセージを受け渡すためのパイプ役として機能し、デバイス同士の連携を図るオブジェクトです。タッチパネルをメディエータの候補にすることも考えられますが、技術的に言えば、タッチパネルはスーパーがベンダーから購入する、ダムデバイスの1つにすぎません。セルフレジシステム自身に専用のメディエータを用意する必要があるでしょう。
Mediatorパターンの例を示すために、先ほどのユースケースの最初の2項目だけを検討します。リスト1に、関連するサブシステムのインターフェースを示します。
// 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); }
Scanner
インターフェースは非常にシンプルなシステムです。読み取り部にバーコードがかざされるまで待機し、バーコードを読み取ったら、そのバーコードを指定のリスナー(ScannerListener
)に送り、次のバーコードの入力待ち状態に戻ります。
TouchScreenDisplay
インターフェースは、タッチパネルデバイスの機能の半分、すなわち顧客が操作を行うための情報をモニターに表示させる部分を受け持ちます。説明を単純にするため、ここで示すインターフェースは、購入記録を表示できるようにする目的のみに制限します。セルフレジの手順をすべてサポートするには、メニュー、確認メッセージ、エラーメッセージなどの表示に関する機能をはじめ、さらに多くのメソッドをこのインターフェースに用意する必要があるでしょう。また、もう1つのインターフェースには、payNow()
、selectPaymentMethod()
など、顧客のタッチパネル操作を取り込む機能が必要でしょう。
Inventory
サブシステムは、店舗のデータベースを検索し、指定のバーコードに対応する価格と商品情報を返します。