定義
定義了對象間一對多的依賴關係,當一個對象(主題Subject)狀態發生改變時,所依賴它的對象(觀察者Observer)將得到通知並自動更新狀態。
主題接口一般包含的方法:
- RegisterObserver(Observer o):註冊新的觀察者
- RemoveObserver(Observer o):刪除舊的觀察者
- Notify(…):通知觀察更新
觀察者接口一般包含相應的收到通知進行更新操作。
優點:
- 依賴接口編程,能夠使不同系統通過低耦合的方式進行通信,減少了不相關係統間代碼的耦合。
- 容易實現一對多的依賴關係,只需要維護一個Observer數組就能給不同對象發送通知。
缺點:
- Observer數組需要進行動態內存管理
- 通知信息是遍歷Observer數組依次發送,在處理多線程問題時可能出現差錯,前一個對象事件處理時間較長會造成下一個對象事件延遲。若觀察者對象間存在聯繫,在執行順序不同時可能會產生差錯。
例子
遊戲角色系統(Subject)給UI系統(Observer)發送通知,實現實時顯示角色血量狀態。
Subject接口:
public void UpdataINFO(int hp, int mp)
{
throw new System.NotImplementedException();
}
Observer口
public interface IObserver {
//更新角色血量藍量信息
void UpdataINFO(int hp, int mp);
}
角色系統(PlayerControl)
public class PlayerControl : MonoBehaviour,ISubject {
//維護一個觀察者對象數組
private List<IObserver> observes;
private int Hp = 100;
private int Mp = 100;
public GameObject UI;
private UIManager uiManager;
// Use this for initialization
void Start () {
observes = new List<IObserver>();
//用例中手動加入 實踐中可以動態加入觀察者數組。
uiManager = UI.GetComponent<UIManager>();
observes.Add(uiManager);
}
// Update is called once per frame
void Update () {
if(Input.GetKey(KeyCode.W))
{
EatHpbag();
}
if(Input.GetKey(KeyCode.S))
{
EatMpbag();
}
}
public void NotifyObserve()
{
for(int i=0;i<observes.Count;i++)
{
observes[i].UpdataINFO(Hp, Mp);
}
}
public void RegisterObserve(IObserver observer)
{
observes.Add(observer);
}
public void RemoveObserve(IObserver observer)
{
int i = observes.IndexOf(observer);
if(i>=0)
{
observes.RemoveAt(i);
}
}
public void EatHpbag()
{
Hp++;
NotifyObserve();
}
public void EatMpbag()
{
Mp++;
NotifyObserve();
}
}
UI系統(UIManager)
public class UIManager : MonoBehaviour, IObserver {
public GameObject HpText;
public GameObject MpText;
private Text Hp;
private Text Mp;
// Use this for initialization
void Start () {
Hp = HpText.GetComponent<Text>();
Mp = MpText.GetComponent<Text>();
}
public void UpdataINFO(int hp, int mp)
{
Hp.text = hp.ToString();
Mp.text = mp.ToString();
}
}