观察者模式
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
个人观点:观察者模式应该被事件所替代。这个模式没有未来。
介绍
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
观察者:Observer
被观察者:Subject. Subject包含有一个Observer列表,以便发生了变换的时候,进行通知。
如何解决:使用面向对象技术,可以将这种依赖关系弱化。
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点:
1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
吐槽(重要)
观察者模式有很大的局限性。那就是:一个Observer只能有一个Subject.
否则问题就出现了:
问题
假设我们设计了观察者模式的基类Observer和Subject,模块需要的时候,只要继承就可以了。假设代码是这样的:
1 | using UnityEngine; |
1 | using UnityEngine; |
看起来很美好, 但是这里会有这么几个问题:
- Observer想要注册监听的时候,怎么找到Subject?
为了向对应的Subect进行注册,没有解耦Observer和Subject。此时,很有可能Subject需要是一个静态唯一的实例。 - 加入Subject发生了A变换,调用了Notify()方法进行通知,项目做着做着,Subject又可以发生B变换了,也需要进行通知。这个时候怎么办?
- 在Notify添加通知变换的类型。但是,如果是项目初始阶段,怎么能预估有没有其他的变换类型呢?如果添加了类型,但是最后没有用到,到后期
review代码的时候,会令人很疑惑。 - 或者是没发生一处变换,就添加一个NotifyX()的基类方法。但是这样的话,到工程后期,只要一发生变化,就可能需要处理很多代码。
- 在Notify添加通知变换的类型。但是,如果是项目初始阶段,怎么能预估有没有其他的变换类型呢?如果添加了类型,但是最后没有用到,到后期
- 假设Subject有n个通知,而不同类型的观察者要监听的通知是不同的。那么岂不是会有即使用不到,但是ObserverX也需要有所有的调用接口吗?
- 假设某个类ObserverBoss要观察多个Subject,比如SubjectA,SubjectB,SubjectC…
这个时候遇到的问题是,SubjectA,SubjectB,SubjectC实现的是同一个onNotify()接口,怎么能确定当ObserverBoss的onNotify方法被调用时,
是谁发生了变化?发生了什么变化?
而如果要解决这个问题,又需要大费周章的进行整套观察者模式的修改。所有涉及到的代码,都需要修改! - 涉及到删除观察者的时候:当ObserverX收到onNotify()之后,做完事情之后ObserverX就不需要观察Subject了。这个时候,如果直接调用了
Subject.RemoveObserver(this),但是Subject的列表还在循环,这个时候会导致OutOfRange的报错或者其他报错。 - 当你已经处理好了所有问题,某一天突然出了一个bug,需要查找,发现是Subject.Notify调用的某一个ObserverX.OnNOtify出的问题。但是到底是哪一个呢?
综上:观察者模式的局限性是在是太大了!!修改和阅读成本也很高!!!
除非能保证一个Observer只观察一个Subject,否则不要使用!!