標籤:觀察者模式 設計 耦合 可擴充 對象
定義:觀測者模式定義了一種一對多的依賴關係,讓多個觀測者對象同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知所有觀測者對象,使它們能夠自動更新自己。
結構圖:
Subject類,可翻譯為主題或抽象通知者,一般用一個抽象類別或者一個介面實現。它把所有對觀察者對象的引用儲存在一個聚集裡,每個主題都可以有任何數量的觀察者。抽象主題提供一個介面,可以增加和刪除觀測者。
Observe類,抽象觀測者,為所有的具體觀察者定義一個介面,在得到主題的通知時更新自己。這個介面叫更新介面。抽象觀察者一般用一個抽象類別或者一個介面實現。更新介面通常包含一個Update()方法,這個方法叫做更新方法。
ConcreteSubject類,叫做具體主題或具體通知者,將有關狀態存入具體觀察者對象;在具體主題的內部狀態改變時,給所有登記過的觀察者發出通知。具體主題角色常用一個具體子類實現。
ConcreteObserver類,具體觀察者,實現抽象觀察者角色所要求的更新介面,以便使本身的狀態與主題的狀體相協調。具體觀察者角色可以儲存一個指向具體主題對象的引用。具體觀察者角色通常用一個具體子類實現。
特點:觀察者模式所做的工作其實就是在解除耦合。讓耦合的雙方都依賴於抽象,而不是依賴於具體。從而使得各自的變化都不會影響到另一邊的變化。
適用地方:當一個對象的改變不要同時改變其他對象的時候,而且它不知道具體有多少對象有待改變時,應該考慮使用觀察者模式。
不足:“抽象通知者”還是依賴“抽象通知者”,也就是說,萬一沒有了抽象觀察者這樣的介面,我這通知的功能就完不成了。另外就是每個具體觀察者,它不一定是‘更新’的方法就調用,就像剛才說的,我希望的是‘工具箱’是隱藏,‘自動視窗’是開啟,這根本就不是同名的方法。這應該就是不足的地方吧。
委託的相關知識:
委託就是一種引用方法的類型。一旦為委託分配了方法,委託將與該方法具有完全相同的行為。委託方法的使用可以像其他任何方法一樣,具有參數和返回值。委託可以看作是對函數的抽象,是函數的‘類’,委託的執行個體將帶便一個具體的函數。
一個委託可以搭載多個方法,所有方法被依次喚醒。更重要的是,它可以使得委派物件所搭載的方法並不需要屬於同一個類。委派物件所搭載的所有方法必須具有相同的原型和形式,也就是擁有相同的參數列表和返回值類型。
基本代碼:
using System;
using System.Collections.Generic;
using System.Text;
namespace 觀察者模式
{
class Program
{
static void Main(string[] args)
{
ConcreteSubject s = new ConcreteSubject();
s.Attach(new ConcreteObserver(s, "X"));
s.Attach(new ConcreteObserver(s, "Y"));
s.Attach(new ConcreteObserver(s, "Z"));
s.SubjectState = "ABC";
s.Notify();
Console.Read();
}
}
abstract class Subject
{
private IList<Observer> observers = new List<Observer>();
//增加觀察者
public void Attach(Observer observer)
{
observers.Add(observer);
}
//移除觀察者
public void Detach(Observer observer)
{
observers.Remove(observer);
}
//通知
public void Notify()
{
foreach (Observer o in observers)
{
o.Update();
}
}
}
//具體通知者
class ConcreteSubject : Subject
{
private string subjectState;
//具體通知者狀態
public string SubjectState
{
get { return subjectState; }
set { subjectState = value; }
}
}
abstract class Observer
{
public abstract void Update();
}
class ConcreteObserver : Observer
{
private string name;
private string observerState;
private ConcreteSubject subject;
public ConcreteObserver(
ConcreteSubject subject, string name)
{
this.subject = subject;
this.name = name;
}
//更新
public override void Update()
{
observerState = subject.SubjectState;
Console.WriteLine("觀察者{0}的新狀態是{1}",
name, observerState);
}
public ConcreteSubject Subject
{
get { return subject; }
set { subject = value; }
}
}
}