设计模式(十九)观察者
一、定義
定義對象之間的一種一對多依賴關(guān)系,使得當每一個對象狀態(tài)發(fā)生改變時,其相關(guān)依賴對象皆得到通知并被自動更新。觀察者模式是一種行為型模式,又稱為發(fā)布-訂閱(Publish-Subscribe)模式、模型-視圖(Model-View)模式、源-監(jiān)聽器(Source-Listener)模式或從屬者(Dependents)模式。
二、描述
觀察者模式是一種使用頻率最高的設(shè)計模式之一,用于建立一種對象與對象之間的依賴關(guān)系,一個對象發(fā)生改變時將自動通知其他對象,其他對象將相應作出反應。包含以下四個角色:1、Subject(抽象目標):又稱為主題,是被觀察的對象。
2、ConcreteSubject(具體目標):抽象目標的子類,通常包含有經(jīng)常發(fā)生改變的數(shù)據(jù),當它的狀態(tài)發(fā)生改變時,向其各個觀察者發(fā)出通知。
3、Observer(抽象觀察者):觀察者將對觀察目標的改變做出反應。
4、ConcreteObserver(具體觀察者):具體觀察者中維持一個指向具體目標對象的引用,它用于存儲具體觀察者的有關(guān)狀態(tài),這些狀態(tài)需要和具體目標地狀態(tài)保持一致。
三、例子
X公司欲開發(fā)一款多人聯(lián)機對戰(zhàn)游戲,在游戲中,多個游戲玩家可以加入同一戰(zhàn)隊組成聯(lián)盟,當戰(zhàn)隊中某一成員收到敵人攻擊時將給所有其他盟友發(fā)送通知,盟友收到通知后將作出響應。IObserver:抽象觀察者
public interface IObserver
{
string Name { get; set; }
void Help(); // 聲明支援盟友的方法
void BeAttacked(AllyControlCenter acc); // 聲明遭受攻擊的方法
}
Player:戰(zhàn)隊成員類,充當具體觀察者
public class Player : IObserver
{
public string Name { get; set; }
public void BeAttacked(AllyControlCenter acc)
{
Console.WriteLine("{0}:我正被攻擊,速來援救!", this.Name);
// 調(diào)用戰(zhàn)隊控制中心類的通知方法來通知盟友
acc.NotifyObserver(this.Name);
}
public void Help()
{
Console.WriteLine("{0} :堅持住,立馬來救你!", this.Name);
}
}
AllyControlCenter:抽象戰(zhàn)隊控制中心類,充當抽象目標
public abstract class AllyControlCenter
{
public string AllyName { get; set; }
protected IList<IObserver> playerList = new List<IObserver>();
public void Join(IObserver observer)
{
playerList.Add(observer);
Console.WriteLine("通知:{0} 加入 {1} 戰(zhàn)隊", observer.Name, this.AllyName);
}
public void Quit(IObserver observer)
{
playerList.Remove(observer);
Console.WriteLine("通知:{0} 退出 {1} 戰(zhàn)隊", observer.Name, this.AllyName);
}
// 聲明抽象通知方法
public abstract void NotifyObserver(string name);
}
ConcreteAllyControlCenter:具體戰(zhàn)隊控制中心類,充當具體目標
public class ConcreteAllyControlCenter : AllyControlCenter
{
public ConcreteAllyControlCenter(string allyName)
{
Console.WriteLine("系統(tǒng)通知:{0} 戰(zhàn)隊組建成功!", this.AllyName);
Console.WriteLine("-------------------------------------------------------");
this.AllyName = allyName;
}
// 實現(xiàn)通知方法
public override void NotifyObserver(string playerName)
{
Console.WriteLine("通知:盟友們,{0} 正遭受敵軍攻擊,速去搶救!", playerName);
foreach (var player in playerList)
{
if (!player.Name.Equals(playerName, StringComparison.OrdinalIgnoreCase))
{
player.Help();
}
}
}
}
Program:測試代碼
// Step1.定義觀察者對象
AllyControlCenter acc = new ConcreteAllyControlCenter("金庸群俠");
// Step2.定義4個觀察者對象
IObserver playerA = new Player() { Name = "楊過" };
acc.Join(playerA);
IObserver playerB = new Player() { Name = "令狐沖" };
acc.Join(playerB);
IObserver playerC = new Player() { Name = "張無忌" };
acc.Join(playerC);
IObserver playerD = new Player() { Name = "段譽" };
acc.Join(playerD);
// Step3.當某盟友遭受攻擊
playerA.BeAttacked(acc);
Console.ReadLine();
四、總結(jié)
1、優(yōu)點
(1)觀察者模式可以實現(xiàn)表示層和數(shù)據(jù)邏輯層的分離,定義了穩(wěn)定的消息更新傳遞機制、并抽象了更新接口,使得可以有各種各樣不同的表示層充當具體觀察者角色。
(2)在觀察目標和觀察者之間建立一個抽象的耦合,觀察目標只需要維持一個抽象觀察者的集合,無須了解其具體觀察者。由于觀察目標和觀察者沒有緊密地耦合在一起,因此它們可以屬于不同的抽象化層次。
(3)觀察者模式支持廣播通信,觀察目標會向所有已注冊的觀察者對象發(fā)送通知,簡化了一對多系統(tǒng)設(shè)計的難度。
(4)觀察者模式符合開閉原則,增加新的具體觀察者無須修改原有系統(tǒng)代碼,在具體觀察者與觀察目標之間不存在關(guān)聯(lián)關(guān)系的情況下增加新的觀察目標也很方便。
2、缺點
(1)如果一個觀察目標對象有很多直接和間接觀察者,將所有的觀察者都通知到會花費很多時間。
(2)如果在觀察者和觀察目標之間存在循環(huán)依賴,觀察目標會觸發(fā)它們進行循環(huán)調(diào)用,可能導致系統(tǒng)崩潰。
(3)觀察者模式?jīng)]有相應的機制讓觀察者知道所觀察的目標對象是怎么發(fā)生變化的,而只是知道觀察目標發(fā)生了變化。
總結(jié)
以上是生活随笔為你收集整理的设计模式(十九)观察者的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript forEach 方
- 下一篇: Windows下使用图形化的Havoc