
Observer を C# で
Observer は、 振る舞いに関するデザインパターンの一つで、 オブジェクトが別のオブジェクトに状態の変化を通知できるようにします。
Observer パターンは、 サブスクライバー・インターフェースを実装するいかなるオブジェクトのイベント通知の申し込みと停止をする方法を提供します。
複雑度:
人気度:
使用例: Observer パターンは、 C# コードではよく見かけます。 特に、 GUI コンポーネントで。 他のオブジェクトで起きるイベントに、 そのクラスに結合することなく、 反応する方法を提供します。
見つけ方: このパターンは、 オブジェクトをリストに保存するサブスクリプション・メソッドと、 そのリスト中のオブジェクトの更新メソッドの呼び出しにより、 識別できます。
概念的な例
この例は、 Observer デザインパターンの構造を説明するためのものです。 以下の質問に答えることを目的としています:
- どういうクラスからできているか?
- それぞれのクラスの役割は?
- パターンの要素同士はどう関係しているのか?
Program.cs: 概念的な例
using System;
using System.Collections.Generic;
using System.Threading;
namespace RefactoringGuru.DesignPatterns.Observer.Conceptual
{
public interface IObserver
{
// Receive update from subject
void Update(ISubject subject);
}
public interface ISubject
{
// Attach an observer to the subject.
void Attach(IObserver observer);
// Detach an observer from the subject.
void Detach(IObserver observer);
// Notify all observers about an event.
void Notify();
}
// The Subject owns some important state and notifies observers when the
// state changes.
public class Subject : ISubject
{
// For the sake of simplicity, the Subject's state, essential to all
// subscribers, is stored in this variable.
public int State { get; set; } = -0;
// List of subscribers. In real life, the list of subscribers can be
// stored more comprehensively (categorized by event type, etc.).
private List<IObserver> _observers = new List<IObserver>();
// The subscription management methods.
public void Attach(IObserver observer)
{
Console.WriteLine("Subject: Attached an observer.");
this._observers.Add(observer);
}
public void Detach(IObserver observer)
{
this._observers.Remove(observer);
Console.WriteLine("Subject: Detached an observer.");
}
// Trigger an update in each subscriber.
public void Notify()
{
Console.WriteLine("Subject: Notifying observers...");
foreach (var observer in _observers)
{
observer.Update(this);
}
}
// Usually, the subscription logic is only a fraction of what a Subject
// can really do. Subjects commonly hold some important business logic,
// that triggers a notification method whenever something important is
// about to happen (or after it).
public void SomeBusinessLogic()
{
Console.WriteLine("\nSubject: I'm doing something important.");
this.State = new Random().Next(0, 10);
Thread.Sleep(15);
Console.WriteLine("Subject: My state has just changed to: " + this.State);
this.Notify();
}
}
// Concrete Observers react to the updates issued by the Subject they had
// been attached to.
class ConcreteObserverA : IObserver
{
public void Update(ISubject subject)
{
if ((subject as Subject).State < 3)
{
Console.WriteLine("ConcreteObserverA: Reacted to the event.");
}
}
}
class ConcreteObserverB : IObserver
{
public void Update(ISubject subject)
{
if ((subject as Subject).State == 0 || (subject as Subject).State >= 2)
{
Console.WriteLine("ConcreteObserverB: Reacted to the event.");
}
}
}
class Program
{
static void Main(string[] args)
{
// The client code.
var subject = new Subject();
var observerA = new ConcreteObserverA();
subject.Attach(observerA);
var observerB = new ConcreteObserverB();
subject.Attach(observerB);
subject.SomeBusinessLogic();
subject.SomeBusinessLogic();
subject.Detach(observerB);
subject.SomeBusinessLogic();
}
}
}
Output.txt: 実行結果
Subject: Attached an observer.
Subject: Attached an observer.
Subject: I'm doing something important.
Subject: My state has just changed to: 2
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event.
ConcreteObserverB: Reacted to the event.
Subject: I'm doing something important.
Subject: My state has just changed to: 1
Subject: Notifying observers...
ConcreteObserverA: Reacted to the event.
Subject: Detached an observer.
Subject: I'm doing something important.
Subject: My state has just changed to: 5
Subject: Notifying observers...