观察者模式

159 阅读2分钟

观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系当一个对象的状态改变时,其所有依赖对象都会收到通知。观察者模式主要解决了一个对象改变时,如何自动的通知其他依赖对象,同时保持对象间的低耦合和高协作性

结构

观察者模式主要包含以下几个核心角色

  • Subject:被观察者,它是状态发生变化的对象,负责维护所有依赖于自己的观察者列表,并在状态发生变化时通知所有观察者。
  • Observer:观察者,是接受Subject状态变化通知的对象,当收到通知时做出相应的更新。
  • Concrete Subject:具体被观察者对象
  • Concrete Observer:具体观察者对象

具体实现

  • IObserver.cs 观察者接口
public interface IObserver{
	// 主题状态变化通知回调
	void OnNotify();
}
  • ISubject.cs 被观察者接口
public interface ISubject{
	// 添加观察者
	void AddObserver();
	// 移除观察者
	void RemoveObserver();
	// 状态变化通知观察者
	void Notify();
}
  • ConcreteObserver.cs 实际观察者
public class ConcreteObserver : IObserver {
	public void OnNotify()
	{
	    // ...
	}
}
  • ConcreteSubjtect.cs 实际被观察者
public class ConcreteSubjtect : ISubject {
	private List<IObserver> observerList = new List<IObserver>();
	public void AddObserver(IObserver observer)
	{
		observers.Add(observer);
	}
	
	public void RemoveObserver(IObserver observer)
	{
		observers.Remove(observer);
	}

	public void Notify()
	{
		foreach (var observer in observers)
		{
		    observer.OnNotify();
		}
	}   
}
  • 观察者模式UML类图

观察者模式UML类图.png

改善

  • 使用双向链式观察者列表可以减少数组的动态分配,同时也可以用常量时间移除观察者。
  • 链表节点池 由于我们使用观察者对象作为链表节点,这使得观察者和被观察者的关系被固定了,如果我们希望一个观察者可以观察多个被观察者,那只能在一个状态中定义不同类型的被观察者,这样才能匹配不同的观察者。反之我们可以在改变观察者列表的结构,如下图,这样观察者就能存在多个被观察者的列表。

链表节点池.jpg

销毁时需要做的事

  • 当一个观察者被删除时,被观察者也许任然持有它的指针,此时被观察者如果试图发送一个通知的话,将会抛出一个空引用的错误。或者是UI界面频繁的打开关闭,在每次打开时注册观察者对象,而每次关闭的时候没有取消观察者对象的注册,这使得观察者列表无限增长,最终UI界面对象僵死在内存中。一个安全的方案是在每个观察者被销毁时,让观察者自动取消注册,这意味着每个观察者都需要保存一个被观察者的引用。
  • 被观察者销毁时要做的事情就很简单了,你需要清空观察者列表,并且可以在销毁前给观察者列表发送一个”死亡通知“。