行为型模式:观察者模式
十一大行为型模式之七:观察者模式。
简介
姓名 :观察者模式 英文名 :Observer Pattern 价值观 :盯着你怎么着 个人介绍 : Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically. 定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。 (来自《设计模式之禅》)
你要的故事
想来想去,就拿我们现在生活中最常体会到的事情来讲观察者模式--朋友圈。小明、小红、小东 3 人是好朋友,最近他们的父母都给安排了手机,刚用上手机那是相当的兴奋呀。他们立马从 QQ 转投到微信的怀抱,对微信的朋友圈玩的不亦乐乎,什么事情都往上面发。突然有一天,小明和小红因为一些小事争执闹别扭了,原因就是他们对一道数学题有不同的见解。就跟我们小时候和朋友玩得好好的,突然因为一点小事就闹翻了。小红比较孩子气,立马就屏蔽了小明的朋友圈,不想再看到有关小明相关的信息。故事就是这么一回事,关注点就在这朋友圈
上。朋友圈就是运用观察者模式的一个很好的样例。为什么这么说?我们发朋友圈的时候,那些没有屏蔽我们朋友圈的好友,会收到信息推送。也就是没有屏蔽我们朋友圈的好友其实是订阅了我们朋友圈,好友相当于观察者,我们是被观察的对象。符合观察者模式这个关系。
我们通过代码来描述小明、小红、小东他们在朋友圈玩的场景。利用观察者模式,需要观察对象和被观察对象,所以我们先定义 2 个接口,分别是 Observable
(可被观察接口) 和 Observer
(观察者接口)。
实现 Observable
接口的对象说明是可被订阅观察的,所以它需要 addObserver()
新增订阅者方法和 removeObserver()
移除订阅者方法,另外还有一个是必须的,就是通知各个订阅者消息的方法 notifyObservers()
。那 Observable
接口代码如下所示。
interface Observable { void addObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers(String message); }
实现 Observer
接口的对象说明是可以去订阅观察的,也就是说可以接收被订阅的对象发出来的消息,那就需要一个接收消息的方法 update()
。代码如下所示。
interface Observer { void update(String name, String message); }
为了让大家不混淆,先把观察者和被观察者分离开,其实在这个例子中,观察者和被观察者是同一个对象 User
的。这里就分开,分成 User
和 Friend
,后面会给出正确的代码,稍安勿躁哈。这里 User
作为被观察者,实现了 Observable
接口,而 Friend
作为观察者,实现了 Observer
接口。代码如下。
class User implements Observable { private List<Observer> friends; private String name; public User(String name) { this.name = name; this.friends = new LinkedList<>(); } public void sendMessage(String message) { this.notifyObservers(message); } @Override public void addObserver(Observer observer) { this.friends.add(observer); } @Override public void removeObserver(Observer observer) { this.friends.remove(observer); } @Override public void notifyObservers(String message) { this.friends.forEach(friend -> { friend.update(this.name, message); }); } } class Friend implements Observer { private String name; public Friend(String name) { this.name = name; } @Override public void update(String name, String message) { System.out.println("【" + this.name + "】看到【" + name + "】发的朋友圈:" + message); } } public class ObserverTest { public static void main(String[] args) { User xiaoMing = new User("小明"); Friend xiaoHong = new Friend("小红"); Friend xiaoDong = new Friend("小东"); xiaoMing.addObserver(xiaoHong); xiaoMing.addObserver(xiaoDong); xiaoMing.sendMessage("今天真开心"); // 小红和小明闹别扭了,小红取消订阅小明的朋友圈 xiaoMing.removeObserver(xiaoHong); xiaoMing.sendMessage("希望明天也像今天一样开心"); } } 打印结果: 【小红】看到【小明】发的朋友圈:今天真开心 【小东】看到【小明】发的朋友圈:今天真开心 【小东】看到【小明】发的朋友圈:希望明天也像今天一样开心
看到代码执行结果,小红和小东都订阅了小明的朋友圈,小明发了朋友圈:今天真开心。他们俩都收到了,因为小红和小明闹别扭,小红取消订阅小明的朋友圈,所以小明后来发的朋友圈,小红没收到。
上面代码其实是不对的,不应该用 User
和 Friend
2 个类来定义。如果小明订阅小红和小东的朋友圈呢?这样实现比较麻烦,主要是为了分清 观察者
和 被观察者
这 2 个概念,通过上面的例子应该分清楚了 2 个概念了,那就可以来看正确的代码,小明、小红、小东他们其实都是观察者和被观察者,所以我们用 User2
来定义他们就可以,User2
实现了 Observable
和 Observer
接口。代码如下。
class User2 implements Observable, Observer { private List<Observer> friends; private String name; public User2(String name) { this.name = name; this.friends = new LinkedList<>(); } @Override public void addObserver(Observer observer) { this.friends.add(observer); } @Override public void removeObserver(Observer observer) { this.friends.remove(observer); } @Override public void notifyObservers(String message) { this.friends.forEach(friend -> { friend.update(this.name, message); }); } @Override public void update(String name, String message) { System.out.println("【" + this.name + "】看到【" + name + "】发的朋友圈:" + message); } public void sendMessage(String message) { this.notifyObservers(message); } } public class ObserverTest { public static void main(String[] args) { User2 xiaoMing2 = new User2("小明"); User2 xiaoHong2 = new User2("小红"); User2 xiaoDong2 = new User2("小东"); xiaoMing2.addObserver(xiaoHong2); xiaoMing2.addObserver(xiaoDong2); xiaoMing2.sendMessage("今天真开心"); xiaoMing2.removeObserver(xiaoHong2); xiaoMing2.sendMessage("希望明天也像今天一样开心"); xiaoHong2.addObserver(xiaoMing2); xiaoHong2.addObserver(xiaoDong2); xiaoHong2.sendMessage("今天和小明吵架了,屏蔽他的朋友圈"); xiaoDong2.addObserver(xiaoMing2); xiaoDong2.addObserver(xiaoHong2); xiaoDong2.sendMessage("小明和小红吵架了,夹在中间好尴尬"); } } 打印结果: 【小红】看到【小明】发的朋友圈:今天真开心 【小东】看到【小明】发的朋友圈:今天真开心 【小东】看到【小明】发的朋友圈:希望明天也像今天一样开心 【小明】看到【小红】发的朋友圈:今天和小明吵架了,屏蔽他的朋友圈 【小东】看到【小红】发的朋友圈:今天和小明吵架了,屏蔽他的朋友圈 【小明】看到【小东】发的朋友圈:小明和小红吵架了,夹在中间好尴尬 【小红】看到【小东】发的朋友圈:小明和小红吵架了,夹在中间好尴尬
从代码中,我们看到小明、小红、小东 3 个人互相订阅朋友圈,当然中途小红屏蔽了小明的朋友圈。这就是 观察者
和 被观察者
刚好是同一个对象的实现。
总结
观察者模式
是一个比较特殊的设计模式,它定义了触发机制,观察者只要订阅了被观察者,就可以第一时间得到被观察者传递的信息。在工作中,使用观察者模式的场景也比较多,比如消息队列消费,Android 开发中的事件触发机制等等。好,观察者模式就到这。
推荐阅读:
设计模式系列文章持续更新中,欢迎关注公众号 LieBrother,一起交流学习。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
深入分析Kubernetes DaemonSet Controller
Author: xidianwangtao@gmail.com | Version: Kubernetes 1.13 摘要:DaemonSet是Kubernetes中用户最常用的对象之一,我们用它来部署Nodes上守护应用,比如日志组件、节点监控组件等。从用户的使用角度来讲,DaemonSet看似简单,但实际上它涉及的点非常多,比如DaemonSet Pod满足什么条件才能在Node上运行、Node出现MemoryPressure或者其他异常Condition时是否能运行、调度的逻辑是怎样的、滚动更新的逻辑是怎样的等等,本文讲从DaemonSet Controller的源码着手,分析其中关键逻辑。 DaemonSet Controller DaemonSet Controller Struct DaemonSet Controller的核心结构包括: burstReplcas int: 每次sync时,Create和Delete Pods的数量上限,代码中写死为250。 queue workqueue.RateLimitingInterface: 存放待同步DaemonSet Key(...
- 下一篇
踏入职场后,差距来自哪里
混迹职场多年后,免不了要跟以前的同学或同事聚上一聚,聊一聊职场人生,感悟一下时光匆匆,顺便怀念一下当年。这时候一个尴尬或者拉仇恨的话题可能会摆上桌面「这几年混的怎么样?」,为什么尴尬,混的好的当然不存在,主要是对混的一般没什么成就的人来说,就略显尬尴。同样的年纪,同样的学历,同样的起点,几年后,为何个人能力、贫富差距,眼界格局差距如此之大 ?这些年到底发生了什么,何以带来如此的差距 ?今天就来说一说这个事情。 一、环境 还记得以前的自己在关于环境这个问题上一直认为,如果没打算在一线这种城市扎根,那就不要出去,回来后需要从头积累,而且一线生活成本较高,税后收入刨去生活成本跟在二线其实差不了太多,我相信很多人都听过类似的话。后来我就认为这就是正确的。后来的后来我发现,我错了,搞IT有机会还是得去一线,去大厂。 作为it行业从业人员,平台太重要了,信息也太重要了,有时候不是能力的问题,而是知不知道的问题,知不知道这是眼界和见识决定的,这种平台和机会一线城市显然要优于二三线城市,那二三线也不是完全没机会,只是相对小很多,我们当然应该去搏大概率事件。 拿个技术问题举例来说,「分布式事务」,微服...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Hadoop3单机部署,实现最简伪集群
- CentOS8编译安装MySQL8.0.19
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2全家桶,快速入门学习开发网站教程