Observerパターン
Observerパターン
Observerパターンとは、「クラスから通知を発行する仕組み」と、「他のクラスから発行された通知を受け取る仕組み」を実現するためのデザインパターンです。
主に、以下のような状況において特に有用です。
双方向ではなく、一方からもう一方へと一方通行でデータを発行する場合。
1回ではなく、複数回データを発行する場合。
任意のタイミングでデータを発行したい場合。
発行されたデータを、複数のクラスが同時に受け取りたい場合。
ざっくりいいかえれば、「いつ起こるかわからない処理」に有用。
ObserverとObservable
Observer・・・「データを受け取るクラス」のこと。監視者。
Observable・・・「データを発行するクラス」のこと。監視されうるもの。
基本的な仕組み
ObserverがObservableにデータの発行先として登録する。
Observableは登録されたすべての発行先に値を発行する
Observerは受け取った値を使用して任意の処理を実行する
1.ObserverがObservableにデータの発行先として登録する。
// observerA が Observableにデータの発行先として登録
observable.Subscribe(observerA);
// observerB が Observableにデータの発行先として登録
observable.Subscribe(observerB);
ObserverがObservableにデータの発行先として登録することを、「購読(Subscribe)する」と言います。
※「AさんはS社の雑誌を定期購読する」といった表現からくると思われる。
2.Observableは登録されたすべての発行先に値を発行する
Observableは、発行する値ができると、値の発行先として登録されたすべてのObserverに対して一斉に値を発行します。
// すべてのObserverに対して一斉にvalueを発行
observer.OnNext(value);
3.値を受け取ったときのコールバック処理を記述する
各メソッドにそれぞれ通知が来たときに実行したい処理(いつ起こるかわからない処理)を自由に記述します。
// .NET Framework4.0以降には、Observerパターンで使えるIObserver<T>インターフェイスとIObservable<T>インターフェイスがSystem名前空間に標準で用意されています。
public class Observer : IObserver<int>
{
private string m_name;
public Observer(string name)
{
m_name = name;
}
public void OnCompleted()
{
Console.WriteLine($"通知の受け取りが完了しました");
}
public void OnError(Exception error)
{
Console.WriteLine($"次のエラーを受信しました:{error.Message}");
}
public void OnNext(int value)
{
Console.WriteLine($"{value}を受け取りました");
}
}
Observableの実装例
public class Observable : IObservable<int>
{
//購読されたIObserver<int>のリスト
private List<IObserver<int>> m_observers = new List<IObserver<int>>();
public IDisposable Subscribe(IObserver<int> observer)
{
if(!m_observers.Contains(observer))
m_observers.Add(observer);
//購読解除用のクラスをIDisposableとして返す
return new Unsubscriber(m_observers, observer);
}
public void SendNotice()
{
//すべての発行先に対して1,2,3を発行する
foreach (var observer in m_observers)
{
observer.OnNext(1);
observer.OnNext(2);
observer.OnNext(3);
}
}
//購読解除用内部クラス
private class Unsubscriber : IDisposable
{
//発行先リスト
private List<IObserver<int>> m_observers;
//DisposeされたときにRemoveするIObserver<int>
private IObserver<int> m_observer;
public Unsubscriber(List<IObserver<int>> observers, IObserver<int> observer)
{
m_observers = observers;
m_observer = observer;
}
public void Dispose()
{
//Disposeされたら発行先リストから対象の発行先を削除する
m_observers.Remove(m_observer);
}
}
}
使用例
class Program
{
static void Main(string[] args)
{
//値を受け取るクラスを3つ作成
Observer observerA = new Observer("Aさん");
Observer observerB = new Observer("Bさん");
Observer observerC = new Observer("Cさん");
//値を発行するクラスを作成
Observable observable = new Observable();
//3つのObserverが、自分自身を発行先として登録する(=購読)
IDisposable disposableA = observable.Subscribe(observerA);
IDisposable disposableB = observable.Subscribe(observerB);
IDisposable disposableC = observable.Subscribe(observerC);
Console.WriteLine("Aさん〜Cさんが値を購読しました");
Console.WriteLine("値を発行させます");
//Observableに値を発行させる
observable.SendNotice();
Console.ReadKey();
}
}
この記事が気に入ったらサポートをしてみませんか?