洞察探索open banking如何通过小程序容器技术助力金融企业实现数据安全和数字化转型
652
2022-11-02
百度工程师教你玩转设计模式(观察者模式)
要写好代码,设计模式(Design Pattern)是必不可少的基本功,设计模式是对面向对象设计(Object Oriented Design)中反复出现的问题的一种有效解决方案,本次从比较常见的观察者模式入手(Observer Pattern)。在观察者模式中,存在多个观察者对象依赖(Observer)都依赖同一个目标对象(Subject),当被依赖的目标对象发生变化的时候,会通知所有依赖它的观察者对象,然后各个观察者对象根据自己的需要做出对应的响应。
其主要优点如下:
降低了目标与观察者之间的耦合关系 建立了目标与观察者之间的变化触发机制
其主要缺点如下:
目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率
比较抽象不好理解?我们来参考日常功能设计中几个常见的场景。
01观察者模式在天气预报场景的应用
关注天气预报是我们日常生活中一个比较重要的习惯,不同的角色对于天气的变化由有着不同的反应。例如明天特大暴雨,气象部门考虑的是评估并发布合理的政策指导,教育部门需要评估是否需要停课,应急部门考虑的是如何提前准备应急救援,环卫部门需要准备暴雨后的大量环卫工作,打工人需要考虑如何上下班通勤,也存在一些不受此次暴雨影响地区的人什么也不需要考虑。结合上述观察者模式的介绍,在此场景中,天气属于被各个角色依赖的目标对象(Subject),气象/教育/应急/环卫等部门,打工人,其他地区的人都属于观察者对象(Observer)。目标对象发生变化后,各个观察者对象收到消息后都会作出对应的响应措施。基于以上场景实现的简化版观察者模式类图如下:
目标对象(WeatherSubject):即被观察的目标对象,即本例中的天气,持有一个天气状态的属性state,以及绑定观察者的方法attach(),观察者的方法notifyAllObservers()。当状态发生变更后,调用notifyAllObservers()方法通知所有观察者。 抽象观察者对象(Observer):用于定义各个观察者的行为规范,也可以采用接口的方式实现 实际观察者对象:MeteorologicalDepartment、RescueDepartment、OfficeWorker、Other等,实际需要关注目标对象并作出响应的角色。继承自抽象观察者对象,并基于各自的关注点实现了对于的响应方法update()。
基于以上示例的Java版代码demo试下:
package com;
import java.util.ArrayList;
import java.util.List;
// 基于天气预报场景的观察者模式实现Demo
public class ObserverPatternDemo {
// 天气对象
static class WeatherSubject {
private int state;
List
02 观察者模式在支付场景中的应用
在支付业务场景下,用户购买一件商品,当支付成功之后三方会回调自身,在这个时候系统可能会有很多需要执行的逻辑(如:更新订单状态,发送短信通知,通知物流系统开始备货,赠送礼品…)。
通常最直观的处理方式,会创建对应支付系统需要依赖的类(Order、SMS、Express...)以及支付类Pay,在支付主逻辑中实例化各依赖类,当用户支付成功后,逐个调用各依赖类处理逻辑。但这样支付类要了解需要通知哪些类,且支付主逻辑臃肿耦合也较重,不便于扩展和维护。
观察者模式则可以更好的处理这种支付场景,这些支付系统所依赖的类逻辑之间并没有强耦合,因此适合使用观察者模式去实现这些功能,对与支付类来说不关心需要通知哪些类,只需要提供通知列表,当有更多的操作时,只需要向通知列表中添加新的观察者即可,用户支付成功通知所有注册的观察者。实现了对修改关闭,对扩展开放的开闭原则。
具体实现上通常包括以下几部分:
抽象出被观察者Observable类,抽象出共有的属性和方法; 创建具体被观察者Pay类,只要用户支付成功,它就要去通知所有注册的观察者; 抽象出观察者接口Observer,它包含了一个更新自己的抽象方法update,当接到具体主题Pay的更改通知时被调用; 创建订单、短信、物流等具体观察者类,它们要观察支付状态,得到Pay的更改通知时更新自身的状态;
// 抽象主题(Subject)角色
public abstract class Observable {
// 观察者列表
private List
03 观察者模式在数据订阅场景的应用
在实际应用中,数据推送的场景下,经常会用到观察者模式。以小说资源为例,新的章节生产完成后,需要该数据的业务很多,如搜索、网盘、贴吧、小度等,各方接收数据的方式各异。
对于每个订阅方,会实现截然不同的订阅方法,可能是推送Observer { public function push($data); } class Publish { private $observers = array(); public function register(Observer $observer) { $this->observers[] = $observer; } public function delete(Observer $observer) { $index = array_search($observer, $this->observers); if ($index !== FALSE && array_key_exists($index, $this->observers)) { unset($this->_observers[$index]); } } public function push($data) { foreach ($this->observers as $observer) { $observer->push($data); } } } class Search implements Observer { public function push($data) { //推送afs } } class Cloud implements Observer { public function push($data) { //推送kafaka } } $publish = new Publish(); $publish->register(new Search()); $publish->register(new Cloud()); $publish->push($data);
04 总结
通过对以上三个实际案例的讲解和具体的代码实现阅读,大家对观察者模式的应用场景和具体实现方案应该有了更加深入的了解了。结合以上三个案例的的分析,适合观察者模式的场景都有以下典型特征:
存在多对一的依赖关系:即多个观察者依赖同一个目标对象 存在目标变更触发机制:目标变更后,需要触发一系列的其他任务
通过观察者机制来实现以上场景,可以实现目标类和观察者类的解耦,即目标对象无需知道需要通知哪些观察者,方便后续的扩展与维护。
---------- END ----------
推荐阅读【技术加油站】系列:
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~