问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

【设计模式】快速理解观察者模式,原来它还有这么多其他名字

发布网友 发布时间:2024-10-02 03:17

我来回答

1个回答

热心网友 时间:2024-10-10 09:09

(一)什么是观察者模式

我们都关注了某个公众号,当这个公众号发文章时,所有关注它的人都会收到一条消息通知。这种当一个对象被修改时,会自动通知依赖它的对象的动作抽象为设计模式就是观察者模式

(二)观察者模式中的角色

观察者模式中主要有四个角色:

Subject:被观察对象的抽象类,这个角色还承担了注册观察者和删除观察者的方法。

ConcreteSubject:具体的被观察对象,在开头的例子中,某个公众号就是一个具体的被观察对象。

Observer:观察者的接口,负责接收被观察对象的状态变化并更新。

ConcreteOberver:具体的观察者,在开头的例子中,每个关注公众号的人就是具体的观察者。

(三)观察者模式的案例

只看概念很难理解这种设计模式究竟是干什么的,接下来就通过一个具体的例子来感受一下,这个例子还是采用文章开头公众号的例子。 首先定义Observer接口,负责更新操作。

public?interface?Observer?{????/**?????*?更新操作?????*?@param?subject?????*/????public?abstract?void?update(Subject?subject);}

上面代码中的Subject是被观察对象的抽象类,这个类定义了添加观察者、删除观察者、通知观察者的方法,并定义了获取标题和生成文章的两个抽象方法:

public?abstract?class?Subject?{????/**?????*?记录所有的观察者?????*/????private?ArrayList<Observer>?observers?=?new?ArrayList<>();????/**?????*?添加观察者?????*?@param?observer?????*/????public?void?addObservers(Observer?observer){????????observers.add(observer);????}????/**?????*?删除观察者?????*?@param?observer?????*/????public?void?deleteObservers(Observer?observer){????????observers.remove(observer);????}????/**?????*?通知所有的观察者?????*/????public?void?notifyObservers(){????????for(Observer?observer:observers){????????????observer.update(this);????????}????}????/**?????*?获取文章标题?????*/????public?abstract?String?getTitle();????/**?????*?生成一篇文章?????*/????public?abstract?void?createArticle();}

接着定义具体的被观察对象,这里是一个具体的公众号,并实现获取标题和创建文章的抽象方法:

public?class?ConcreteSubject?extends?Subject{????private?String?title;????@Override????public?String?getTitle()?{????????return?title;????}????@Override????public?void?createArticle()?{????????System.out.println("创建了一篇文章");????????this.title="这是文章标题";????????this.notifyObservers();????}}

接下来创建两个观察者:

public?class?OneObserver?implements?Observer{????@Override????public?void?update(Subject?subject)?{????????System.out.println("One收到了一篇推送,标题为"+subject.getTitle());????}}public?class?TwoObserver?implements?Observer{????@Override????public?void?update(Subject?subject)?{????????System.out.println("Two收到了一篇推送,标题为"+subject.getTitle());????}}

最后通过Main类进行测试:

public?class?Main?{????public?static?void?main(String[]?args)?{????????//创建具体的被观察者对象????????Subject?concreteSubject?=?new?ConcreteSubject();????????//创建两个具体的观察者????????Observer?oneObserver?=?new?OneObserver();????????Observer?twoObserver?=?new?TwoObserver();????????//两个具体的观察者关注了被观察者对象????????concreteSubject.addObservers(oneObserver);????????concreteSubject.addObservers(twoObserver);????????//被观察者对象创建了一篇文章????????concreteSubject.createArticle();????????//第一个观察者取消关注????????concreteSubject.deleteObservers(oneObserver);????????//被观察者对象又创建了一篇文章????????concreteSubject.createArticle();????}}

最终的运行结果如下:

创建了一篇文章One收到了一篇推送,标题为这是文章标题Two收到了一篇推送,标题为这是文章标题创建了一篇文章Two收到了一篇推送,标题为这是文章标题(四)观察者模式在源码中的应用

在JDK的java.util包下,直接提供了观察者模式所需要的Observer和Subject对象。其中Observer对象和我在第三章定义的十分相似:

package?java.util;public?interface?Observer?{????void?update(Observable?o,?Object?arg);}

Subject对象在这个包下名称叫做Observable,包含了添加观察者,删除观察者等操作。

package?java.util;public?class?Observable?{????private?boolean?changed?=?false;????private?Vector<Observer>?obs;????public?Observable()?{????????obs?=?new?Vector<>();????}????public?synchronized?void?addObserver(Observer?o)?{????????if?(o?==?null)????????????throw?new?NullPointerException();????????if?(!obs.contains(o))?{????????????obs.addElement(o);????????}????}????public?synchronized?void?deleteObserver(Observer?o)?{????????obs.removeElement(o);????}????public?void?notifyObservers()?{????????notifyObservers(null);????}????public?void?notifyObservers(Object?arg)?{????????Object[]?arrLocal;????????synchronized?(this)?{????????????if?(!changed)????????????????return;????????????arrLocal?=?obs.toArray();????????????clearChanged();????????}????????for?(int?i?=?arrLocal.length-1;?i>=0;?i--)????????????((Observer)arrLocal[i]).update(this,?arg);????}????public?synchronized?void?deleteObservers()?{????????obs.removeAllElements();????}????protected?synchronized?void?setChanged()?{????????changed?=?true;????}????protected?synchronized?void?clearChanged()?{????????changed?=?false;????}????public?synchronized?boolean?hasChanged()?{????????return?changed;????}????public?synchronized?int?countObservers()?{????????return?obs.size();????}}(五)总结

观察者模式在不同的场景下还有不同的叫法,比如在本文的例子中,观察者模式叫做发布-订阅(publish-Subscribe)模式会更合适;观察者模式还可以叫做源-监听器(Source-Listener)模式,但是不管怎么叫,它的定义都是相同的。

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
八月中国最凉快的地方 八月份哪里最凉快,去哪旅游好?美丽的地方 乱字同韵字是什么意思 华硕笔记本电脑触摸板怎么开笔记本电脑触摸板怎么开启和关闭_百度知 ... 陕西职务侵占案立案准则 结婚后我的恋情维系了十年,怎么做到的? 玉米仁子饭产自哪里 中国期货交易所的交易品种有哪些? 历史要怎么读,有啥诀窍 高中历史诀窍 三分钟快速上手Spring事件机制 【python小脚本】Yaml配置文件动态加载 车开10年了还能开吗 孙晓晓和苏醒是因为什么原因传绯闻啊? 《舞动奇迹》里说孙骁骁和苏醒“有事”,这是怎么回事? 赵本山演的小品[功夫]在哪个网站能看? 中国绿茶中最好的前十种 大家说,我要不要给刘强东打个电话 视力疲劳症状 苹果手机系统一直不更新有什么后果? 视力疲劳的症状 视力疲劳视力疲劳的症状 某种甘蔗的出糖率为百分之十二那么要榨得0.66吨蔗糖需要甘蔗多少吨 卢思浩的书有哪些 ...出一种优质甘蔗,400吨可以榨出64吨蔗糖,普通甘蔗400吨只能榨出52... 我想问一下天津有没有规定在此买房居住多少年户口就可以迁过来呢? ...优质的甘蔗,400吨可以榨出64吨蔗糖。现在这种甘蔗3 已经设置密保为什么我的QQ修改密码只有短信验证没有密保问题选择。_百 ... 为什么我的QQ有密保 却不能修改密码 说是≮根据您帐号当前的安全情况... 现在办理招商银行的信用卡需要什么材料吗 《我和春天有个约会》结局 如何下载花椒直播视频 怎样去除电脑图标上的小锁图标? 63式履带式装甲车族结构特点 电脑微信聊天记录如何导到手机上去 M113A1-B履带式装甲人员输送车型号演变和变型车 女生主动把以前的很多照片发给你看,什么意思? 你知道什么是隐私浏览器吗? 什么浏览器隐私功能最强大? UC浏览器存在泄露隐私问题吗? ...在电脑没有网络时怎么把手机QQ下载的文件传到电脑上? 弥勒一日游,怎样更有意义? 昆明到弥勒泡温泉攻略,昆明周边旅游一日游包车 的辅食牛肉小水饺,小馄饨.怎么做如何 次韵子瞻武昌西山作品赏析 次韵子瞻武昌西山作者简介 “凭凌霄汉乘风雷”的出处是哪里 次韵子瞻武昌西山作品原文 自己梦见死了的老人家叫我把我女儿送一个给她是什么意思? 华为智选值得购买的智能家居产品