さて、前回のエントリでは、コメントにてεπιστημηさんととっちゃんさんに、『「イベント」はObserverパターンそのまんまやんけ』とツッコミをいただいたわけですが、今回は前回のコードを「イベント」を使って書き直してみます。
では、さっそく例を。
- イベント引数を定義する。 メンバとしてfrom, to, subjectを持ち、それぞれの読み取り専用プロパティを定義する。
class NewMailEventArgs : EventArgs
{
private readonly string from;
private readonly string to;
private readonly string subject;
public NewMailEventArgs(string from, string to, string subject)
{
this.from = from;
this.to = to;
this.subject = subject;
}
public string From
{
get { return this.from; }
}
public string To
{
get { return this.to; }
}
public string Subject
{
get { return this.subject; }
}
}
- SubjectであるMailManagerクラスを定義する。 内部にはイベントNewMailを持ち、通知メソッドはデリゲートによるメソッド呼び出しを行う。
class MailManager
{
public event EventHandler<NewMailEventArgs> NewMail;
private void Notify(NewMailEventArgs e)
{
NewMail(this, e);
}
public void SetData(string from, string to, string subject)
{
NewMailEventArgs e = new NewMailEventArgs(from, to, subject);
Notify(e);
}
}
- ObserverであるFaxクラス、Printerクラスを定義する。 それぞれ、通知を受けたときの動作を記述します。
class Fax
{
public void Notify(object sender, NewMailEventArgs e)
{
Console.WriteLine("Faxを送信します。");
Console.WriteLine("From:{0}, To:{1}, Subject:{2}", e.From, e.To, e.Subject);
}
}
class Printer
{
public void Notify(object sender, NewMailEventArgs e)
{
Console.WriteLine("印刷します。");
Console.WriteLine("From={0}, To={1}, Subject={2}", e.From, e.To, e.Subject);
}
}
以上のコードを実行してみます。
実行用コード
class ObserverEventTest
{
static void Main(string[] args)
{
// MailManagerインスタンス生成
MailManager mm = new MailManager();
// Faxを登録
Fax fax = new Fax();
mm.NewMail += fax.Notify;
// データ設定、通知
Console.WriteLine("1回目");
mm.SetData("わんくま同盟", "まさる", "勉強会の連絡");
// Printerを登録
Printer printer = new Printer();
mm.NewMail += printer.Notify;
// データ設定、通知
Console.WriteLine("2回目");
mm.SetData("わんくま同盟", "まさる", "補足");
// Faxを削除
mm.NewMail -= fax.Notify;
// データ設定、通知
Console.WriteLine("3回目");
mm.SetData("わんくま同盟", "まさる", "訂正");
}
}
実行結果
1回目
Faxを送信します。
From:わんくま同盟, To:まさる, Subject:勉強会の連絡
2回目
Faxを送信します。
From:わんくま同盟, To:まさる, Subject:補足
印刷します。
From=わんくま同盟, To=まさる, Subject=補足
3回目
印刷します。
From=わんくま同盟, To=まさる, Subject=訂正
前回と同じ結果が得られました。
さて、前回のコードと比べて、今回のコードの違いは何でしょうか。思いつくところでは、
- インターフェースの定義が不要になった。
- 専用のEventArgsの定義が必要になった。
- SubjectにObserverを登録、削除するためのメソッド定義が不要になった。
- SubjectにObserverのコレクションが不要になり、代わりにイベントメンバが必要になった。
- Subjectに登録するのがObserver自体ではなく、Observerのメソッドになった。
といったところでしょうか。
上記内容より、前回に比べた利点を簡単にまとめると以下のようになります。
「イベント」を使うことによりコーディング量を削減でき、また共通のインターフェースを実装していなくとも、シグネチャが一致すればどんなクラスにも通知が可能。
というわけで、C#,VB.NETでObserverパターンが必要になったら、「イベント」を積極的に使う方向でいこうと思います。使わないほうがいいようなときがあったらツッコミをお願いします。
#こんな感じで「ないす」なところが説明出来ているでしょうか?>επιστημηさん
※今回扱ったイベント周りは、「プログラミング .NET Framework 第2版」の「第10章 イベント」にて詳しく解説されています。