たとえばGUIアプリケーションで、いろいろなウィンドウが、あるイベントのオブザーバーになっていて、そのイベントが発生したら通知をしてもらいたいとします。こういう場合、たとえば
interface Observer { void update(); }
ってインタフェースと、イベント発生時にイベントをObserverへ通知するSubjectクラス:
class Subject { private IList<Observer> observers = new List<Observer>(); public void notifyObservers() { foreach (var observer in observers) { observer.update(); } } public void addObserver(Observer observer){ observers.Add(observer);} public void removeObserver(Observer observer) { observers.Remove(observer); } }
を作成したりします。んで、それぞれのウィンドウクラスが、このObserverの実装クラスをつくってSubjectに登録、なんてことをやると思います。
あ、C#だったらObserverインタフェースとかじゃなくてdelegateでしょ!ってツッコミはおいておきます。後でやってみます。
さて、各ウィンドウが登録したObserverなインスタンスは、その登録したウィンドウが破棄されたらちゃんとSubjectから破棄する必要があるわけですが、それが自動で出来るように弱参照という機構を使ってみようと思います。
まずは弱参照をつかわないでベタにこんな感じ。フィールドにObserverをもってSubjectに登録するようなウィンドウクラスをつくってます。
abstract class IWindow { public Subject Subject { get; set; } public IWindow(Subject subject) { this.Subject = subject; } public abstract void init(); } class MyWindow : IWindow { private Observer observer; public MyWindow(Subject subject, String name) : base(subject) { observer = new MyObserver(name); } public override void init() { base.Subject.addObserver(observer); } }
メインクラスはこんな感じ。
class Program { public static void Main(string[] args) { Subject subject = new Subject(); // Observerを持ったウィンドウクラスを作成。 IWindow window1 = new MyWindow(subject, "ウィンドウ1"); window1.init(); IWindow window2 = new MyWindow(subject, "ウィンドウ2"); window2.init(); // なんかイベントが発生したとかで、subjectがObserverたちに通知。 subject.notifyObservers(); window1 = null; //ウィンドウ1への参照がなくなったので、Subjectから削除したいのだけど GC.Collect(); subject.notifyObservers(); } }
途中でwindow1をnullにしてウィンドウ1への参照がなくなっても、実行結果は
ウィンドウ1 にイベントが通知されました ウィンドウ2 にイベントが通知されました ウィンドウ1 にイベントが通知されました ウィンドウ2 にイベントが通知されました
ってウィンドウ1のイベントハンドラが呼び出されてしまいます。ココはほんとうはwindow1=nullにしてウィンドウ1がGCされたときに、Subjectからobserverを削除したいわけですね。
この記事は
現在のアクセス:6058