文章整理转载自:https://www.cnblogs.com/yssjun/p/11107038.html
观察者模式:就是指多个对象间存在一对多的关系,当被观察者状态发生改变时,所有观察者都得到通知并自动更新。这种模式有时又称作发布-订阅模式。
1. 目的
建立对象间一对多的关联关系,并能使一个对象的变化被所有关联对象感知。
2. 动机
建立一套低耦合的消息触发机制。
3. 优缺点
优点:
- 被观察者和观察者之间是抽象耦合的;
- 耦合度较低,两者之间的关联仅仅在于消息的通知;
- 被观察者无需关心他的观察者;
- 支持广播通信;
缺点:
- 观察者只知道被观察对象发生了变化,但不知变化的过程和缘由;
- 观察者同时也可能是被观察者,消息传递的链路可能会过长,完成所有通知花费时间较多;
- 如果观察者和被观察者之间产生循环依赖,或者消息传递链路形成闭环,会导致无限循环;
4. 应用场景
- 需要在系统中建立一个单项广播的触发机制;
- 系统中某个对象的行为会影响若干其他对象;
- 对象之间的关联关系可以在运行时动态的建立与撤销;
- 对象之间的关联关系呈现出一种树状结构;
5. 原理
下面是GoF介绍的典型的类观察者模式的UML类图:
Subject:
抽象被观察者,仅提供注册和删除观察者对象的接口声明。
ConcreteSubject:
具体被观察者对象,该对象中收集了所有需要被通知的观察者,并可以动态的增删集合中的观察者。当其状态发生变化时会通知所有观察者对象。
Observer:
抽象观察者,为所有观察者定义获得通知的统一接口;
ConcreteObserver:
观察者对象,其关注对象为Subject,能接受Subject变化时发出的通知并更新自身状态。
6.实现
//抽象观察者
abstract class Observer{
public abstract void update();
}
//具体观察者
class ConcreteObserver : Observer
{
public override void update()
{
Console.WriteLine("观察者状态跟随更新");
}
}
//抽象被观察者
abstract class Subject
{
private List<Observer> observers = new List<Observer>();
public void Add(Observer obs) {
Console.WriteLine("添加了新观察者");
observers.Add(obs);
}
public void Remove(Observer obs)
{
observers.Remove(obs);
}
public void Notify()
{
Console.WriteLine("被观察者状态更新");
foreach (Observer observer in observers)
{
observer.update();
}
}
}
//具体被观察者
class ConcreteSubject : Subject
{
}
测试代码:
static void Main(string[] args)
{
Subject s = new ConcreteSubject();
Observer obs = new ConcreteObserver();
s.Add(obs);
s.Notify();
}
输出结果:
- 关于委托(类似观察者模式):
委托是一种函数指针。一旦为委托分配了方法,委托将与该方法有相同的行为。委托可以添加多个方法,当使用委托调用方法时,所有添加到委托的方法都会被调用,有点像被观察者与观察者的关系。 - 关于事件:
事件基于委托,为委托提供了一种发布/订阅机制。事件的订阅与取消与我们刚才讲的观察者模式中的订阅与取消类似,只是表现形式有所不同。在观察者模式中,订阅使用方法Attach()来进行;在事件的订阅中使用“+=”。类似地,取消订阅在观察者模式中用Dettach(),而事件的取消用“-=”。
既然是委托,其实说到底他还是方法的集合,当执行事件后,这个集合中的所有方法都会被执行;
区别在于,委托可以在委托所属的类外面进行添加和删除操作;但是事件不行,事件只能在事件所属的类内部进行添加和删除操作,所以也可以说事件是受限的委托。