觀察者模式:
定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主體對象。這個主題對象在狀態發生變化時,會通知所有觀察者對象,使它們自動更新自己。
現實聯想:
這個模式就好像小偷偷東西,有一個或者多個人放哨(通知者),當警察來的時候,放哨的人就會通知偷東西的人(觀察者)趕緊跑。
觀察者模式特點
觀察者模式其實就是降低耦合作用,讓耦合雙方都依賴於抽象而不是依賴於具體。從而使得各自代碼的變化都不會影響另一邊的變化。
總結:
觀察者模式通過通知者檢測某一事務的變化,然後當被檢測事務發生變化的時候,通知者通知觀察者,觀察者根據被檢測事務的變化也隨之變化。
觀察者模式實例
第一步建立通知者抽象類
abstract class Subject
{
public 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; }
}
}
第五步客戶端代碼
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.ReadKey();
}
}
觀察者模式的不足
在我們所使用的軟件中,有些較爲複雜的軟件,當隨着主體對象的變化而變化的事務都是封裝好的這就不是觀察者模式所能解決的的了
比如當主體對象發生變化的時候,觀察者都封裝在不同的房間(封裝),如觀察者一在A房間,觀察者二在B房間,觀察者三在C房間,這樣他們就不能像觀察者模式中那樣在一個房間內工作,當一個通知到的時候,他們將會都知道通知的內容。這樣無法滿足通知所有觀察者的要求。這個時候我們就要應用到事件委託
建立委託事件
Delegate void EventHandler();
第一步 :書寫通知者代碼
interface Subject //主體代碼接口
{
void Notify();
string SubjectState//主體狀態
{
get;
set;
}
}
delegate void EventHandler();
class Boss :Subject//主體的實例類
{
public event EventHandler Update;
private string action;
public void Notify()
{
Update();
}
public string SubjectState
{
get { return action; }
set { action = value; }
}
}
第二步寫觀察者代碼,
因爲主體通知後,因爲有的觀察者是單獨封裝的,所有的觀察者不一定都能繼承Observer,所以Oberver父類就沒有存在的必要,因此只需要寫具體的觀察者類就行了
class Stockobserver
{
private string name;//觀察者姓名
private Subject sub;//用來存儲主體的狀態
public Stockobserver (string name,Subject sub )
{
this.name = name;
this.sub = sub;
}
public void ColseStockMarket()
{
Console.WriteLine("{0}{1}關閉股市行情,繼續工作!", sub.SubjectState , name);
}
}
class NBAObeserver
{
private string name;
private Subject sub;
public NBAObeserver (string name,Subject sub )
{
this.name = name;
this.sub = sub;
}
public void CloseNBAdirectSeeding()
{
Console.WriteLine("{0}{1}關閉NBA直播,繼續工作!", sub.SubjectState, name);
}
}
客戶端代碼
static void Main(string[] args)
{
Boss huhansan = new Boss();
//將觀察者類實例化
Stockobserver tongshi1 = new Stockobserver("小明", huhansan);
NBAObeserver tongshi2 = new NBAObeserver("小剛", huhansan);
//建立一個新的委託,將這個委託託付給update這個委託類型的事件
//將tongshi1.ColseStockMarket事件委託給huhansan.Update這個事件
huhansan.Update += new EventHandler(tongshi1.ColseStockMarket);
huhansan.Update += new EventHandler(tongshi2.CloseNBAdirectSeeding);
//委託事件就好像是一個集合,可以存儲多個委託
huhansan.SubjectState = "我回來了";
huhansan.Notify();
}