定义
定义了对象间一对多的依赖关系,当一个对象(主题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();
}
}