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