什么是觀察者模式
觀察者模式適用於一對多的應用場景。
有若干觀察者對象,他們依賴於目標對象。當目標對象執行某操作時,所有觀察者對象都會得到通知並自動執行相應操作。
舉個例子:在老頭環中,只要玩家喝血瓶,那么周圍的敵人就會捕獲到這個動作,並立刻發動進攻,讓你喝多少吐多少。
在上述例子里,玩家就是“目標對象”;周圍所有的敵人就是“觀察者對象”。玩家喝血即“目標對象執行某操作”,而所有敵人都會接收到玩家喝血的廣播,然后立刻發動攻擊,即“執行對應操作”。
實現手段
在說實現手段前,我還是想強調:設計模式始終是思想,具體的實現手段各不相同。
這里我使用事件來實現,你也可以讓目標持有所有觀察者的引用來實現等等。
定義一個抽象目標基類 BaseSubject ,其他目標類均繼承自它
public abstarct class BaseSubject
{
public event Action CallObservers;
public void CallAllObservers()
{
CallObservers?.Invoke();
}
}
定義一個抽象觀察者基類 BaseObserver ,其他目標類均繼承自它
public abstarct class BaseObserver
{
public abstract void OnEnable();
public abstract void OnDisable();
public abstract void UpdateMyState();
}
某個目標類,繼承自抽象目標基類
public class Subject : BaseSubject
{
private void Start()
{
ChangeState();
}
public void ChangeState()
{
Debug.Log("Player(Subject) : Drink to heal myself.");
CallAllObservers();
}
}
某個觀察者類,繼承自抽象觀察者基類
public class Observer : BaseObserver
{
public BaseSubject subject;
public override void OnEnable()
{
subject.CallObservers += UpdateMyState;
}
public override void OnDisable()
{
subject.CallObservers -= UpdateMyState;
}
public override void UpdateMyState()
{
Debug.Log("Enemy(Observer) : Attack right now!");
}
}
結果如下
優缺點
優點:
- 它降低了對象之間的耦合度,方便使用。
- 它建立起了一套觸發機制,使得不同的觀察者均可以很好地響應目標的廣播,方便代碼拓展。
- 符合迪米特法則(最少知道原則)。
缺點:
- 當觀察者數量過多時,整體響應時間較長。
- 觀察者無從得知目標變化的具體內容,它僅僅知道目標發生了變化。
在老頭環里,部分玩家反過來利用了這一點。在玩家裝填弩箭時,敵人也會“讀指令”,但裝填弩箭的前后搖比喝葯的前后搖短很多,敵人卻無從得知玩家變化的具體內容,僅僅知道玩家賣了個破綻,所以當敵人攻擊時,玩家已經可以發動彈反來反擊了。 - 當觀察者與目標間有循環依賴時,可能發生循環調用致使系統崩潰。
注意:
- 觀察者模式適用於一對多的應用場景。
小結
值得一提的是,觀察者模式尤為契合解謎游戲的需求,采取該模式進行設計開發,可以很大程度上降低開發難度。