Mediator パターン (後編)
2009/01/05 21:11 - デザインパターン
前編からの続き。
ところで Mediator とは一体何なのか。
media すなわち「媒介する者」ということで、解説書では「調停者」などと日本語訳されていますが、その機能を鑑みるにむしろ「司令塔」と考える方がふさわしいように思われます。
複数のインスタンスが協業してひとつのプログラムを実現していても、個々のインスタンスは基本的には自分の仕事をだけを受け持つのがオブジェクト指向的考え方です。 しかしあるインスタンスの変化が他のインスタンスに影響を及ぼすようにしたい場合は多々あります。
1対1ならそのインスタンス同士を連携させれば良いかもしれませんが、その連携が1対多、あるいは多対多のように複雑に入り組んでいる場合、個々のクラスに連携を記述するのは効率的ではありません。
Mediator は仕事の構成員である、連携するインスタンス全員を監視し、ある構成員に変化が発生した際に他の構成員(本人を含む場合も状況によってはあるでしょう)に適切な指示を出す機能を担うものです。
今サンプルの Mediator は、ボタンインスタンス全部を束ね、ボタンインスタンスからマウスダウンが発生しました、という報告を受けると、前回マウスダウンが発生したボタンインスタンスに対して指示を出す、というのがその機能です。
仕事構成員の監視というと Observer パターンというものがあります。 私は Mediator と Observerとは根本的には同じものだと感じました。 その辺りの詳細は稿を改めて書く機会もあるでしょうからそのときにでも。
では実際に Mediator パターンを使ってコーディングしたものを見てみます。
以下、コードの提示。
- Main.as (ドキュメントクラス)
- Button.as (ボタンクラス)
- Mediator.as (Mediator クラス)
まずは今回の主役、Mediator クラスから見てみます。
今サンプルの Mediator はこれで全文。実に単純です。 メンバプロパティに前回押されたボタン。 そして主処理に colleagueChanged()メソッド。 こんだけ。
ところでこの主処理の colleagueChanged()メソッド、public になってます。
一体誰が呼ぶのか? Mediator に監視される側、すなわち Button クラスのインスタンスが呼び出します。
呼び出されるタイミングは? もちろんボタンが押されたとき。
つまりボタンインスタンスは自分自身の上でマウスダウンが発生したとき、「今私が押されました」と Mediator にご注進にあがるわけです。
注進を受けた Mediator は、前回記録されたボタンがあった場合はそれに対してボタン機能復帰を指示し、今注進してきたボタンを「前回押されたボタン」として記録します。
ボタンが押されたときに自らの機能を停止するのは Button クラス自身が担います。 それは個々のボタンインスタンスの自分自身に起きる事象ですからね。
じゃあ次に Button クラスを見てみましょう。
上述の Mediator クラスを媒介させることで、前回はドキュメントクラスに記述したマウスイベントリスナーを、Button クラス内部に実装・隠蔽することができるようになります。
新たな制約としては、Button クラス内部に Mediator を保持するメンバプロパティを置く、Mediator への注進機能(colleagueChanged の呼び出し)を付加する、この二つが必要になります。
各異動は上記のボタンクラス全文の当該箇所を確認していただくとして、以下にマウスイベントハンドラだけを提示します。 Mediator への注進部分ですね。
2行目ですね肝は。Mediator クラスの主処理である colleagueChanged メソッドがここで呼び出されています。
3行目で自分自身のボタン機能を停止させています。 前回 enabledButton メソッドは public だったんですが、今回は private にすることができます。
以上ふたつの連携でマウスイベント時におこないたい処理が実装できました。 そしてドキュメントクラスからイベントリスナーを排除することができました。 ドキュメントクラスのなんとスッキリしたことか。
ちなみにドキュメントクラスで Mediator インスタンスをメンバプロパティにしていますが、この事例では別にメンバプロパティにする必要はないです。 コンストラクタ以外のメソッドから Mediator インスタンスを呼び出すときのことを考え、このようなコーディングにしてあります。
この程度の簡単な処理ならドキュメントクラスに Mediator 機能を持たせてもそれほど煩雑にはなりませんが、数種類のクラスが複数個連携するような複雑な事例では、記述内容も複雑かつ多量になることもあるでしょう。 Mediator を置くとスッキリとしたコーディングが可能になるという寸法です。