Composite Application Guidanceでアプリを組むとモジュールごとに綺麗に?分割されたアプリケーションを作ることが出来る。
そんな疎結合なモジュール同士が連携して動作するための仕組みとしてIEventAggregatorというクラスを利用する。
こいつは、Bootstrapperの中でUnityContainerに登録される。各モジュールは、UnityContainerからIEventAggregatorのインスタンスをインジェクションしてもらって、そいつにイベントの発行命令や、イベントハンドラの登録を行う。
こうやって、モジュール間で強調作業が行える&疎結合な状態を保つことが出来るようになってる。
というわけで、IEventAggregatorの実験をしてみようと思う。実験のためにComposite Application Guidance for WPFのお作法にのっとったアプリケーションを組むのはメンドクサイので、コンソールアプリケーションでお試しをした。
Composite Application GUidance for WPFのクラスの大部分は、普通に単品でも動くように作られてるから、こういうコンソールアプリケーションで要素技術の勉強が出来るようになっている。素敵だ。
プロジェクトの作成
CompositeEventSampleという名前でコンソールアプリケーションを作った。そして、Composite Application Guidance for WPFのdll + Unity + ObjectBuilder2を参照に加える。これで準備完了!
イベントの作成
まず、EventAggregatorに登録するイベントを識別するためのクラスを作る。作り方は簡単で、CompositeWpfEvent<T>というクラスを継承するだけ。<T>の部分には、イベント発生時に引数としt渡す型を指定する。
ということで、string型を渡すSampleEventを定義してみた。
public class SampleEvent : CompositeWpfEvent<string> { }
イベントハンドラの作成
イベントが出来たので、イベントを受けて処理をする人を作ろうと思う。イベントを受けることが出来るのは、Action<T>になる。<T>にはCompositeWpfEvent<T>と同じ型である必要がある。今回の場合は、Action<string>でイベントを受けることが出来る。
イベントを受ける人を登録するメソッドは、IEventAggregatorのGetEvent<TEventType>()の戻り値に定義されているSubscribeメソッドになる。TEventTypeには、先ほど作ったSampleEventを渡すとOK。GetEvent<TEventType>にAction<T>を渡すだけでイベントのリスナー登録完了になります。というわけで早速作る。
class Program
{
static void Main(string[] args)
{
// 普通にnewで作れちゃう。
// 通常は、UnityBootstrapperの中でインスタンスが作られてUnityContainerに
// 登録されている。
IEventAggregator e = new EventAggregator();
// SampleEventが起きたらConsole.WriteLineを呼び出す!
e.GetEvent<SampleEvent>().Subscribe(Console.WriteLine);
}
}
Action<string>に該当するものとして、今回はConsole.WriteLineを使った。もちろん自作のメソッドでも、ラムダ式でも問題ない。
イベントの発行
イベントを定義して、イベントが起きたときの処理も出来上がったので、最後にイベントを発行してみようと思う。
発行も非常に簡単。GetEvent<TEventType>()の戻り値に対してPublishを呼ぶだけで完了になる。Publishの引数には、Subscribeメソッドで登録したAction<T>の引数に渡したいオブジェクトになる。
今回は、Hello worldを渡すように実装してみた。
class Program
{
static void Main(string[] args)
{
// 普通にnewで作れちゃう。
// 通常は、UnityBootstrapperの中でインスタンスが作られてUnityContainerに
// 登録されている。
IEventAggregator e = new EventAggregator();
// SampleEventが起きたらConsole.WriteLineを呼び出す!
e.GetEvent<SampleEvent>().Subscribe(Console.WriteLine);
// イベント発行!!もちろんハローワールド
e.GetEvent<SampleEvent>().Publish("Hello world");
}
}
実行してみよう
実行してみると、Hello worldとコンソールに表示される。
イベント発行の際に渡した引数がConsole.WriteLineにわたっているのがわかると思う。
まとめ
今回のサンプルでは、同一のメソッド内でやったのでありがたみは0だけど、モジュール間でも同じ感覚で引数を渡してイベントを発行できるのでとてもいい!!
今回の例では使わなかった機能で、使いでがありそうなものは、Subscribeメソッドのオーバーライドの1つにあるThreadOptionを渡せるものになると思う。
ThreadOptionには、BackgroundThread, PublisherThread, UIThreadの3つがある。BackgroundThreadは、時間のかかる処理を、PublisherThreadはPublishを呼び出したのと同じスレッドで呼ばれるのでパパッと終わる処理を(デフォルトはこれになる)、UIThreadは、UIの更新を行う処理をするものに向いている。
個人的に、気に入っているのはEventHandlerの呪縛から解き放たれたことかな。