10_02 设计模式-观察者模式
1. 设计模式-观察者模式
认识观察者模式
- 报纸和杂志的订阅
- 报社的业务就是出版报纸
- 向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,你就会一直收到新报纸
- 当你不想再看报纸时,取消订阅
- 观察者模式 = 订阅 + 广播
- 类比:邮局报刊订阅
- 你向邮局订阅报刊
- 邮局把你加入订阅人列表
- 每当有新的报纸,邮局会及时送到每个订阅人手中
- 当你不需要该报纸时,你向邮局退订,从此邮局不再给你送报纸
-
一个报纸对象,会有多个订阅者对象来订阅;当报纸出版的时候,也就是报纸对象改变的时候,需要通知所有的订阅者对象。
-
观察者模式把多个订阅者称为观察者:Observer;多个观察者观察的对象被称为目标:Subject。
-
一个目标可以有任意多个观察者对象,一旦目标的状态发生了改变,所有注册的观察者都会得到通知,然后各个观察者会对通知作出相应的响应,执行相应的业务功能处理,并使自己的状态和目标对象的状态保持一致。
-
发布-订阅(Publish/Subscribe)模式
-
模型-视图(Model/View)模式
-
源-监听器(Source/Listener)模式
-
从属者(Dependents)模式
-
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象/目标。
-
这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己
-
组成:
- 抽象主题/目标角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类或接口来实现。
- 抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
- 具体主题/目标角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。
- 具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。
观察者模式的本质:触发联动
- 当修改目标对象的状态的时候,就会触发相应的通知,然后会循环调用所有注册的观察者对象的相应方法,其实就相当于联动调用这些观察者的方法。
- 这个联动还是动态的,可以通过注册和取消注册来控制观察者,因而可以在程序运行期间,通过动态地控制观察者,来变相地实现添加和删除某些功能处理,这些功能就是观察者在update的时候执行的功能。
- 目标对象和观察者对象的解耦,又保证了无论观察者发生怎样的变化,目标对象总是能够正确地联动过来。
意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
适用性
- 当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用
- 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁
2. 责任链模式/职责链模式
- 责任链模式/职责链模式属于对象的行为型模式。
- 避免将一个请求的发送者与接收者耦合在一起,让多个对象都有机会处理请求。将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止。
- 将请求的处理者组织成一条链,并让请求沿着链传递,由链上的处理者对请求进行相应的处理
- 客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到链上,将请求的发送者和请求的处理者解耦。
- 分析
- 辅导员、系主任、院长、校长都可以处理奖学金申请表,他们构成一个处理申请表的链式结构,申请表沿着这条链进行传递,这条链就称为责任链/职责链
- 责任链可以是一条直线、一个环或者一个树形结构,最常见的职责链是直线型,即沿着一条单向的链来传递请求
责任链模式的结构
- 责任链模式包含以下两个角色:
Handler(抽象处理者)
ConcreteHandler(具体处理者)
责任链模式的优缺点与适用场景
模式优点
- 使得一个对象无须知道是其他哪一个对象处理其请求,降低了系统的耦合度
- 可简化对象之间的相互连接
- 给对象职责的分配带来更多的灵活性
- 增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可
模式缺点
- 不能保证请求一定会被处理
- 对于比较长的职责链,系统性能将受到一定影响,在进行代码调试时不太方便
- 如果建链不当,可能会造成循环调用,将导致系统陷入死循环
模式适用环境
- 有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
- 可动态指定一组对象处理请求
3. 策略模式
- 策略模式属于对象的行为模式。
- 其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。
- 策略模式使得算法可以在不影响到客户端的情况下发生变化。
- 策略模式主要用来平滑地处理算法的切换 。
- Strategy(策略):定义所有支持的算法的公共接口
- ConcreteStrategy(具体策略):实现具体算法
- Context(上下文):
用一个ConcreteStrategy对象来配置
维护一个对Strategy对象的引用
对策略进行二次封装,目的是避免高层模块对策略的直接调用。
例子:
A店除了正常日不打折,在节假日会推出满300减100,全场8折等活动。
特点
- 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。
- 策略模式并不决定在何时使用何种算法。在什么情况下使用什么算法是由客户端决定的。
- 是相同行为的不同实现;使得算法可以独立变化
- 所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少各种算法类与使用算法类之间的耦合。
- 使用组合取代继承,封装了可变性,保证了“开-闭”。
策略模式体现的设计原则
- 组合优先:尽量用组合,而不是继承
- 开-闭原则:增加新功能,要做到只增加新代码,而不改动老代码
- 封装可变性:把变化的代码从不变的代码中分离出来,限制变化的影响范围
- 针对接口编程而不是具体类(定义了策略接口)
END