sh1’s diary

プログラミング、読んだ本、資格試験、ゲームとか私を記録するところ

Prism EventAggregator をなぜ使うべきか

f:id:shikaku_sh:20211013180838p:plain:w400

この記事は、ARCTOUCH のブログ記事「Why you should use Prism EventAggregator in .NET app development」を個人的に雑訳したものです。EventAggregator については「過去の記事」で紹介しています。

Prism は、.NET アプリを開発するための豊富な機能を提供するライブラリーで、C# 開発者のコーディングライフをより快適にする多くの優れた機能を備えています。その機能のひとつが EventAggregator です。この記事では、EventAggregator とはなにか、なぜ便利なのか、そして、どこで使うべきなのかを説明します。

EventAggregator is なに?

要するに、EventAggregator とは Publisher-Subscriber パターンを Prism で実装したものです。Publisher-Subscriber パターンとは、アプリケーションの非同期通信を容易にするため設計されたメッセージングのパターンのことです。具体的には、リンクすることが困難なコンポーネント間でメッセージをやり取りするといった、問題を解決します。

このパターンの核となるものは、event bus に対して発行されるイベントです。event bus は、そのイベントを1つ以上のサブスクライバー (subscribers) に渡します。サブスクライバーは、受け取ったイベントを自由に扱うことができます。

より詳細な情報は「こちら」をご覧ください。

f:id:shikaku_sh:20211027173429p:plain
Publisher-Subscriber パターン

.NET アプリ開発に Prism EventAggregator をなぜ使用するのか?

Publisher-Subscriber モデルには、さまざまなメリットがあります:

  • 分離 (Decoupled)
    パブリッシャーとサブスクライバーはお互いのことを知りません
  • 非同期 (Asynchronous)
    パブリッシャーは、サブスクライバーがイベントの処理を終えるまで待つ必要がないので、メッセージを素早く送信し、自分の処理を続けることができる
  • 関心の分離 (Separation of concerns)
    パブリッシャーはサブスクライバーが何をしているのか知る必要はありません。また、サブスクライバーはイベントがどこで発生したのか知る必要はありません。
  • 拡張性 (Scalable)
    パブリッシャー、サブスクライバー、イベントの数がどれだけ多くても、必要なのは、ひとつのイベントバスへの参照だけ

EventAggregator は、上記の利点に加えて .NET アプリの開発に役に立つ利点を持ちます:

  • モリーリークの防止 (Prevent memory leaks)
    EventAggregator は、廃棄されたサブスクライバの参照を保持しません。マニュアルでサブスクライブを解除する必要もありません
  • 複雑なオブジェクトの送信 (Send complex objects)
    イベントを発行する際に複雑なオブジェクトをパラメーターとして送信して、イベントを処理する際にサブスクライバーにより多くの情報を提供する
  • スレッドの柔軟性 (Thread flexibility)
    受信したイベントを処理するスレッドを選択できる
  • イベントのフィルタリング (Filter events)
    サブスクライバーは、処理するイベントと無視するイベントを選択できる

Prism EventAggregator をいつ利用するのか?

要約すると、Publisher-Subscriber パターンは、リンクすることが難しい、または、現実的ではないコンポーネント間の通信用に設計されたメッセージングのパターンです。

Prism のプロジェクトでは、EventAggregator は、2つ以上の ViewModel の間や、お互いに参照を持たないサービスの間でメッセージを送受信するためによく利用されます。

また、1つのイベントを異なる多くのサブスクライバーで処理する必要があって、それぞれのサブスクライバーにパブリッシャーの参照を渡さない(現実的ではない)ときにも利用されます。

Xamarin.Forms の EventAggregator

Xamarin.Forms に慣れている人は、「待って、Xamarin.Forms には、これに似たものがすでにあるんじゃないか?」と思うかもしれません。確かに、Xamarin.Forms には MessagingCenter という独自の Publisher-Subscriber パターンの実装があります。しかし、以下の理由から私は Prism の EventAggregator が気に入っています:

  • モリーリーク (Memory leaks)
    MessagingCenter は、マニュアルでサブスクライブを解除しないと、参照を保持します。(「Xamarin MessagingCenter memory leaks」で検索すると、パフォーマンスの問題に関する多くのフォーラム投稿を見つけることができます)
  • 柔軟性 (Flexibility)
    MessagingCenter は、EventAggregator のようなスレッドの柔軟性やイベントフィルターはありません
  • テストの容易性 (Testability)
    MessagingCenter は、static メソッドを使用しているため、単体テストの作成が難しいです。Prism では、コンストラクターEventAggregatorインスタンスを注入することができるので、簡単にモックを作成することができます

ちょっとした注意点

ここまでの内容で EventAggregator の柔軟性や有用性について、納得していただけたなら幸いですが、(いつものように、)いくつかの注意点があります。

EventAggregator はサブスクライバーへの弱参照しか持ちませんが、パブリッシャーがパラメーターを渡し、サブスクライバーがその参照を持ち続けている場合は強参照として持つ恐れがあります。このような場合は、サブスクライバーが disposed されたときにマニュアルでサブスクライブを解除するようにしましょう。

また、EventAggregator の Decoupled な(分離された)構造は素晴らしいものですが、使いすぎると複雑さが増してしまいます。

パブリッシャーとサブスクライバーの間には関心の分離がありますが、イベント自体は関心の分離がありません。(イベントは、すべて同じ EventAggregator に保持されます)

多くのイベントを扱う大きなプロジェクトでは、これがコミュニケーションの流れを不明瞭にする恐れがあります。私のアドバイスとしては、EventAggregator は、必要なときにだけ使うようにしましょう。プロジェクト全体を EventAggregator を中心に構築することはやめておきましょう。

なんでもそうですが、節度を守ることが大切です。(Like with everything in life, moderation is key.)

参考