简说设计模式——观察者模式

尼克 等级 366 0 0

一、什么是观察者模式

  观察者一般可以看做是第三者,比如在学校上自习的时候,大家肯定都有过交头接耳、各种玩耍的经历,这时总会有一个“放风”的小伙伴,当老师即将出现时及时“通知”大家老师来了。再比如,拍卖会的时候,大家相互叫价,拍卖师会观察最高标价,然后通知给其它竞价者竞价,这就是一个观察者模式。

  对于观察者模式而言,肯定有观察者和被观察者之分。比如在一个目录下建立一个文件,这时系统会通知目录管理器增加目录,并通知磁盘减少空间,在这里,文件就是观察者,目录管理器和磁盘就是被观察者。

  观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。UML结构图如下:

简说设计模式——观察者模式

  其中,Subject类是主题,它把所有对观察者对象的引用文件存在了一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供了一个接口,可以增加和删除观察者对象;Observer类是抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己;ConcreteSubject类是具体主题,将有关状态存入具体观察者对象,在具体主题内部状态改变时,给所有登记过的观察者发出通知;ConcreteObserver是具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协同。

  1. 主题Subject

  首先定义一个观察者数组,并实现增、删及通知操作。它的职责很简单,就是定义谁能观察,谁不能观察,用Vector是线程同步的,比较安全,也可以使用ArrayList,是线程异步的,但不安全。

 1 public class Subject { 2 
 3     //观察者数组
 4     private Vector<Observer> oVector = new Vector<>();
 5     
 6     //增加一个观察者
 7     public void addObserver(Observer observer) { 8         this.oVector.add(observer);
 9 } 10     
11     //删除一个观察者
12     public void deleteObserver(Observer observer) { 13         this.oVector.remove(observer); 14 } 15     
16     //通知所有观察者
17     public void notifyObserver() { 18         for(Observer observer : this.oVector) { 19 observer.update(); 20 } 21 } 22     
23 }

  2. 抽象观察者Observer

  观察者一般是一个接口,每一个实现该接口的实现类都是具体观察者。

1 public interface Observer { 2     //更新
3     public void update(); 4 }

  3. 具体主题

  继承Subject类,在这里实现具体业务,在具体项目中,该类会有很多变种。

1 public class ConcreteSubject extends Subject { 2 
3     //具体业务
4     public void doSomething() { 5         //...
6         super.notifyObserver(); 7 } 8     
9 }

  4. 具体观察者

  实现Observer接口。

1 public class ConcreteObserver implements Observer { 2 
3 @Override 4     public void update() { 5         System.out.println("收到消息,进行处理"); 6 } 7 
8 }

  5. Client客户端

  首先创建一个被观察者,然后定义一个观察者,将该被观察者添加到该观察者的观察者数组中,进行测试。

 1 public class Client { 2     
 3     public static void main(String\[\] args) { 4         //创建一个主题
 5         ConcreteSubject subject = new ConcreteSubject(); 6         //定义一个观察者
 7         Observer observer = new ConcreteObserver(); 8         //观察
 9 subject.addObserver(observer); 10         //开始活动
11 subject.doSomething(); 12 } 13     
14 }

  运行结果如下:

  简说设计模式——观察者模式

二、观察者模式的应用

  1. 何时使用

  • 一个对象状态改变,所有的依赖对象都将得到通知

  2. 方法

  • 使用面向对象技术

  3. 优点

  • 观察者和被观察者是抽象耦合的
  • 建立了一套触发机制

  4. 缺点

  • 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
  • 如果观察者和观察目标间有循环依赖,可能导致系统崩溃
  • 没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的

  5. 使用场景

  • 关联行为场景
  • 事件多级触发场景
  • 跨系统的消息变换场景,如消息队列的处理机制

  6. 应用实例

  • 手机丢了,委托别人给其他人发消息通知
  • 通知老师/老板来了
  • 拍卖,拍卖师观察最高标价,然后通知给其它竞价者竞价
  • 在一个目录下建立一个文件,会同时通知目录管理器增加目录,并通知磁盘减少空间,文件是被观察者,目录管理器和磁盘管理器是观察者
  • 猫叫了一声,吓着了老鼠,也惊到了主人,猫是被观察者,老鼠和人是观察者

  7. 注意事项

  • 避免循环引用
  • 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式

三、观察者模式的实现

  下面举一个具体实例,假设上班时间有一部分同事在看股票,一部分同事在看NBA,这时老板回来了,前台通知了部分同事老板回来了,这些同事及时关闭了网页没被发现,而没被通知到的同事被抓了个现行,被老板亲自“通知”关闭网页,UML图如下:

简说设计模式——观察者模式

  1. 通知者接口

 1 public interface Subject { 2 
 3     //增加
 4     public void attach(Observer observer); 5     //删除
 6     public void detach(Observer observer); 7     //通知
 8     public void notifyObservers(); 9     
10     //状态
11     public void setAction(String action); 12     public String getAction(); 13     
14 }

  2. 观察者

 1 public abstract class Observer { 2 
 3     protected String name; 4     protected Subject subject; 5     
 6     public Observer(String name, Subject subject) { 7         this.name = name; 8         this.subject = subject; 9 } 10     
11     public abstract void update(); 12     
13 }

  3. 具体通知者

  前台Secretary和老板Boss作为具体通知者,实现Subject接口。这里只给出Secretary类的代码,Boss类与之类似。

 1 public class Secretary implements Subject { 2 
 3     //同事列表
 4     private List<Observer> observers = new LinkedList<>();
 5     private String action; 6 
 7     //添加
 8     @Override
 9     public void attach(Observer observer) { 10 observers.add(observer); 11 } 12 
13     //删除
14 @Override 15     public void detach(Observer observer) { 16 observers.remove(observer); 17 } 18 
19     //通知
20 @Override 21     public void notifyObservers() { 22         for(Observer observer : observers) { 23 observer.update(); 24 } 25 } 26 
27     //前台状态
28 @Override 29     public String getAction() { 30         return action; 31 } 32 
33 @Override 34     public void setAction(String action) { 35         this.action = action; 36 } 37     
38 }

  4. 具体观察者

  StockObserver是看股票的同事,NBAObserver是看NBA的同事,作为具体观察者,继承Observer类。这里只给出StockObserver类的代码,NBAObserver类与之类似。

 1 public class StockObserver extends Observer { 2     
 3     public StockObserver(String name, Subject subject) { 4         super(name, subject);
 5     }
 6 
 7     @Override
 8     public void update() { 9         System.out.println(subject.getAction() + "\\n" + name + "关闭股票行情,继续工作"); 10 } 11 
12 }

  5. 前台作为通知者进行通知(Client)

  前台作为通知者,通知观察者。这里添加adam和tom到通知列表,并从通知列表中删除了adam,测试没在通知列表中的对象不会收到通知。

 1 public class Client { 2 
 3     public static void main(String\[\] args) { 4         //前台为通知者
 5         Secretary secretary = new Secretary(); 6         
 7         StockObserver observer = new StockObserver("adam", secretary);
 8         NBAObserver observer2 = new NBAObserver("tom", secretary);
 9         
10         //前台通知
11 secretary.attach(observer); 12 secretary.attach(observer2); 13         
14         //adam没被前台通知到,所以被老板抓了个现行
15 secretary.detach(observer); 16         
17         //老板回来了
18         secretary.setAction("小心!Boss回来了!"); 19         //发通知
20 secretary.notifyObservers(); 21 } 22     
23 }

  运行结果如下,只有tom接收到了通知:

  简说设计模式——观察者模式

  6. 老板作为通知者进行通知(Client)

  老板作为通知者,通知观察者。这里将tom从老板的通知列表中移除,老板只通知到了adam。

 1 public class Client { 2 
 3     public static void main(String\[\] args) { 4         //老板为通知者
 5         Boss boss = new Boss(); 6         
 7         StockObserver observer = new StockObserver("adam", boss);
 8         NBAObserver observer2 = new NBAObserver("tom", boss);
 9         
10         //老板通知
11 boss.attach(observer); 12 boss.attach(observer2); 13         
14         //tom没被老板通知到,所以不用挨骂
15 boss.detach(observer2); 16         
17         //老板回来了
18         boss.setAction("咳咳,我大Boss回来了!"); 19         //发通知
20 boss.notifyObservers(); 21 } 22     
23 }

  运行结果如下,只有adam挨骂了: 

  简说设计模式——观察者模式

  当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象有待改变的时候,应该考虑使用观察者模式。

  而使用观察者模式的动机在于:将一个系统分割成一系列相互协作的类有一个很不好的副作用,就是需要维护相关对象间的一致性,我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便,而观察者模式所做的工作就是在解除耦合

  源码地址:https://gitee.com/adamjiangwh/GoF

本文转自 https://www.cnblogs.com/adamjwh/p/10913660.html,如有侵权,请联系删除。

收藏
评论区

相关推荐

<Dart基础>Dart简介
Dart基础系列: Dart简介(https://www.jianshu.com/p/c749f40828a5) Dart语法(上)(https://www.jianshu.com/p/6b5689342e24) <基础Dart语法(下)(https://www.jianshu.com/p/7c3eba46e679) 一、简
Dart基础&gt;Dart语法(上)
Dart基础系列: Dart简介(https://www.jianshu.com/p/c749f40828a5) Dart语法(上)(https://www.jianshu.com/p/6b5689342e24) <基础Dart语法(下)(https://www.jianshu.com/p/7c3eba46e679) 说明:
Dart基础语法简介
Dart基础系列: Dart简介(https://www.jianshu.com/p/c749f40828a5) Dart语法(上)(https://www.jianshu.com/p/6b5689342e24) <基础Dart语法(下)(https://www.jianshu.com/p/7c3eba46e679) 一、简
通过一个简单实例了解vuex
简单说明 什么是vuex,vuex怎么使用,什么场景下适合使用vuex, vuex 文档(https://links.jianshu.com/go?tohttps%3A%2F%2Fvuex.vuejs.org%2Fzh%2F)中都有介绍。看完文档之后,都知道vuex的核心有State、Getter、Mutation、Action、Modul
Node.js爬虫实战 - 爬你喜欢的
前言 今天没有什么前言,就是想分享些关于爬虫的技术,任性。来吧,各位客官,里边请... 开篇第一问:爬虫是什么嘞? 首先咱们说哈,爬虫不是“虫子”,姑凉们不要害怕。 爬虫 一种通过一定方式按照一定规则抓取数据的操作或方法。 开篇第二问:爬虫能做什么嘞? 来来来,谈谈需求 产品MM: 1. 爱豆的新电影上架了,整体电影评价如何呢? 2. 暗
简说设计模式——外观模式
一、什么是外观模式   有些人可能炒过股票,但其实大部分人都不太懂,这种没有足够了解证券知识的情况下做股票是很容易亏钱的,刚开始炒股肯定都会想,如果有个懂行的帮帮手就好,其实基金就是个好帮手,支付宝里就有许多的基金,它将投资者分散的资金集中起来,交由专业的经理人进行管理,投资于股票、债券、外汇等领域,而基金投资的收益归持有者所有,管理机
简说设计模式——观察者模式
一、什么是观察者模式   观察者一般可以看做是第三者,比如在学校上自习的时候,大家肯定都有过交头接耳、各种玩耍的经历,这时总会有一个“放风”的小伙伴,当老师即将出现时及时“通知”大家老师来了。再比如,拍卖会的时候,大家相互叫价,拍卖师会观察最高标价,然后通知给其它竞价者竞价,这就是一个观察者模式。   对于观察者模式而言,肯定有观察
一文搞懂什么是HTTP与HTTPS
(https://blog.csdn.net/petterp/article/details/102779257)Http与Https的区别。 在最近的开发中,深感网络相关基础知识薄弱,于是趁周末好好总结一
说说ArrayList的扩容机制
ArrayList是List接口的实现类,它是支持根据需要而动态增长的数组。java中标准数组是定长的,在数组被创建之后,它们不能被加长或缩短。这就意味着在创建数组时需要知道数组的所需长度,但有时我们需要动态程序中获取数组长度。ArrayList就是为此而生的,但是它不是线程安全的,外ArrayList按照插入的顺序来存放数据 ①ArrayList扩容发生
20 张图彻底弄懂 HTTPS 的原理
前言 近年来各大公司对信息安全传输越来越重视,也逐步把网站升级到 HTTPS 了,那么大家知道 HTTPS 的原理是怎样的吗,到底是它是如何确保信息安全传输的?网上挺多介绍 HTTPS,但我发现总是或多或少有些点有些遗漏,没有讲全,今天试图由浅入深地把 HTTPS 讲明白,相信大家看完一定能掌握 HTTPS 的原理,本文大纲如下: HTTP 为什么不安全
给公司面试了100多个前端,心态差点给爷整崩了
公司最近在做扩招,从去年到现在给公司面试前端,到现在大概面了100200个,给我整哭了 简历简历不带,问点基础题,一问三不知, 问个水平垂直居中布局,支支吾吾半天说不出来, 还有个弟弟说你这样问我不知道怎么回答,累了。 我只想说,这真的有三年的经验嘛? (https://imghelloworld.osscnbeijing.aliyu
说说设计模式
设计模式 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总
多人说Python简单,但是如何入门Python并精通?
一般而言,Python几个月就可以开始使用了。假如你几个月没入门,那肯定是方法不对,或者是偷懒.我在公众号里有一篇文章详细写了“初学者别上爬虫”,爬虫虽然很有趣,但不适合于小白用户。以下是2点:多人说Python简单,但是如何入门Python并精通?Python再简单再通俗,它也是一门语言,掌握一门语言绝非一朝一夕,我个人不推荐初学者上岸学习爬虫,我举一个很
https://cloud.tencent.com/developer/article/write/1830331
一、目标今天的目标是这个sign和appcode 二、步骤 Jadx没法上了app加了某梆的企业版,Jadx表示无能为力了。 FRIDADEXDumpDexDump出来,木有找到有效的信息。 Wallbreaker葫芦娃的Wallbreaker可以做些带壳分析,不过这个样本,用Frida的Spawn模式可以载入,Attach模式会失败。而直接用Objecti
手把手教你用Python网络爬虫实现起点小说下载
今天要跟大家分享一个小说爬取案例起点小说的小说下载。在做这个案例之前,我们需要对其进行分析,1.界面分析,如图:通过分析很容易就找到了我们的get请求参数,然后获取相应页面的小说名和链接:获取到数据之后,我们就随机挑选一篇小说来进行下载,我们选第一篇,然后打开它的文章目录,可以看到是这样的,如图:基本上这篇小说很长,可以看到它卷一和卷二是免费的,后面的收费,

热门文章

golang 分析调试高阶技巧Golang常用工具

最新文章

Golang常用工具golang 分析调试高阶技巧