当前位置: 首页 > news >正文

观察者模式

  观察者模式又叫发布-订阅模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。


  观察者模式的特点:将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不变。二观察者模式的关键对象是主题Subject和观察者Object,一个Subject可以有任意数目的依赖他的Observer,一旦Subject的状态发生了改变,所有的Observer都可以得到通知。Subject发出通知时,并不需要知道谁是他的观察者,也就是说,具体观察者是谁,他根本不需要知道。而任何一个具体观察者不知道也不需要知道其他观察者的存在。

 应用场景:
    当一个对象的改变需要同时改变其他对象的时候,而且他不知道具体有多少对象有待改变时,应该考虑使用观察者模式。当一个抽象模型由两方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使他们各自独立的改变和复用。
    观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。(依赖倒转原则的最佳体现)

 

 1 /**
 2  * Observer类,抽象观察者,为所有的具体观察者定义一个接口,
 3  *         在得到主题通知的时候更新自己,这个接口叫做更新接。抽象观察者一般用一个抽象类或者一个接口实现。
 4  *         更新接口通常包含一个update()方法,这个方法叫做更新方法。
 5  * 
 6  * Observer类,抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。
 7  * @author 贤元
 8  *
 9  */
10 public abstract class Observer {
11     public abstract void update();
12 }

 

 

 1 /**
 2  * Subject类,可翻译为主题或抽象通知者,一般用一个抽象类或者一个接口实现。他把所有对观察者对象的引用保存在一个聚集里,
 3  *     每个主题都可以有任何数量的观察者。抽象主体提供一个接口,可以增加和删除观察者对象。
 4  * 
 5  * Subject类,他把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主体提供一个借口,可以增加和删除观察者对象。
 6  * @author 贤元
 7  *
 8  */
 9 public abstract class Subject {
10     
11     //用一个list集合存放观察者
12     private List<Observer> observers = new LinkedList<Observer>();
13     
14     //增加观察者
15     public void attach(Observer observer){
16         observers.add(observer);
17     }
18     
19     //移除观察者
20     public void detach(Observer observer){
21         observers.remove(observer);
22     }
23     
24     //通知。 
25     public void inform(){
26         for(Observer o:observers){
27             o.update(); //通知观察者做出相应变化
28         }
29     }
30     
31 }

 

具体主题:

 1 /**
 2  * ConcreteSubject类,叫做具体主题或具体通知者,将有关状态存入具体观察者对象;
 3  *     在具体主题的内部状态改变时,给所有等级过的观察者发出通知。具体主题角色通常用一个具体子类实现。
 4  * 
 5  * ConcreteSubject类,具体主题,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
 6  * @author 贤元
 7  *
 8  */
 9 public class ConcreteSubject extends Subject{
10     //具体被观察者状态
11     private String subjectState;
12 
13     
14     
15     public String getSubjectState() {
16         return subjectState;
17     }
18 
19     public void setSubjectState(String subjectState) {
20         this.subjectState = subjectState;
21     }
22     
23     
24     
25 }

 

具体观察者:

 1 /**
 2  * ConcreteObserver类,具体观察者,实现抽象观察者橘色所要求的更新接口,以便使本身的状态与主题的状态相协调。
 3  * 具体观察者角色可以保存一个只想具体主题对象的引用。具体观察者角色通常用一个具体子类实现
 4  * 
 5  *ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。
 6  * @author 贤元
 7  *
 8  */
 9 public class ConcreateObserver extends Observer{
10     private String name;//观察者名字
11     private String observerState;//观察者状态
12     private ConcreteSubject subject;//主题。具体观察者(也就是此观察者)所要观察的主题
13     
14     //构造方法,为属性subject和name初始化
15     public ConcreateObserver(ConcreteSubject subject,String name){
16         this.subject = subject;
17         this.name = name;
18     }
19     
20     @Override
21     public void update() {
22         observerState = subject.getSubjectState();
23         System.out.println("观察者"+name+"的更新状态是"+observerState);
24     }
25 
26     
27     
28     public ConcreteSubject getSubject() {
29         return subject;
30     }
31 
32     public void setSubject(ConcreteSubject subject) {
33         this.subject = subject;
34     }
35     
36 }

 测试类:

 1 /**
 2  * 客户端代码
 3  * @author 贤元
 4  *
 5  */
 6 public class TestClient {
 7     public static void main(String[] args) {
 8         //创建主题
 9         ConcreteSubject s= new ConcreteSubject();
10         //为主题添加观察者
11         s.attach(new ConcreateObserver(s,"X"));
12         s.attach(new ConcreateObserver(s,"Y"));
13         s.attach(new ConcreateObserver(s,"Z"));
14         //模拟改变主题的状态
15         s.setSubjectState("ABC");
16         //当主题状态改变时,通知观察该主题的观察者做出相应变化
17         s.inform();
18         
19     }
20 }

运行结果:

  观察者X的更新状态是ABC
  观察者Y的更新状态是ABC
  观察者Z的更新状态是ABC

UML图:

  

 

转载于:https://www.cnblogs.com/lixianyuan-org/p/9504387.html

相关文章:

  • 分表分库之一:分布式数据库的常见用法
  • 主流的CSS水平和垂直居中技术大全
  • 简单工厂、工厂方法和抽象工厂
  • SQLite 多线程模型实测分析
  • 小白都能玩的算法day3-计算机的变革
  • Easyui入门视频教程 第04集---Easyui布局
  • git的安装
  • Visual Studio ALM 词汇表
  • mysql判断两个逗号分隔字符串是否有交集
  • 2018 KDD CUP支付宝安全团队Deep X斩获两项大奖
  • JConsole connection failed
  • tarjan进阶
  • ubuntu13启动屏幕亮度0解决方法
  • 数据结构与抽象 Java语言描述 第4版 pdf (内含标签)
  • 文件尾存在EOF吗?
  • 【跃迁之路】【733天】程序员高效学习方法论探索系列(实验阶段490-2019.2.23)...
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • AWS实战 - 利用IAM对S3做访问控制
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • Git学习与使用心得(1)—— 初始化
  • golang 发送GET和POST示例
  • Javascript设计模式学习之Observer(观察者)模式
  • Linux gpio口使用方法
  • MySQL数据库运维之数据恢复
  • MySQL主从复制读写分离及奇怪的问题
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • PAT A1050
  • Promise初体验
  • webgl (原生)基础入门指南【一】
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 工作中总结前端开发流程--vue项目
  • 回流、重绘及其优化
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 警报:线上事故之CountDownLatch的威力
  • 聚类分析——Kmeans
  • 我建了一个叫Hello World的项目
  • 应用生命周期终极 DevOps 工具包
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ###C语言程序设计-----C语言学习(6)#
  • #etcd#安装时出错
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (9)STL算法之逆转旋转
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (六) ES6 新特性 —— 迭代器(iterator)
  • (五)关系数据库标准语言SQL
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (转)四层和七层负载均衡的区别
  • .NET Standard、.NET Framework 、.NET Core三者的关系与区别?
  • .net 后台导出excel ,word
  • .NET 同步与异步 之 原子操作和自旋锁(Interlocked、SpinLock)(九)
  • .Net各种迷惑命名解释