二十、观察者模式

一、什么是观察者模式

  观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

  观察者模式的主要角色如下:

  • 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
  • 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
  • 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
  • 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

二、观察者模式的实现

  用户可自定义抽象观察者与抽象主题来实现观察者模式,也可通过实现JDK提供的 java.util.Observable 类和 java.util.Observer 接口实现观察者模式。

1. 自定义实现观察者模式

  • 抽象观察者(Observer)
/*** @author FluffyCatkin* @version 1.0* @date 2020/1/7 0007 16:00* @description 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。*/
public interface Observer {void update();
}
  • 抽象主题(Subject)
/*** @author FluffyCatkin* @version 1.0* @date 2020/1/7 0007 16:00* @description 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。*/
public interface Subject {void change();void addObserver(Observer observer);void removeObserver(Observer observer);
}
  • 具体观察者(Concrete Observer)
/*** @author FluffyCatkin* @version 1.0* @date 2020/1/7 0007 15:59* @description 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。*/
public class ConcreteObserver implements Observer {private String name;public ConcreteObserver(String name) {this.name = name;}@Overridepublic void update() {System.out.println("receive......"+name+"is changed.......");}
}
  • 具体主题(Concrete Subject)
/*** @author FluffyCatkin* @version 1.0* @date 2020/1/7 0007 15:59* @description 具体主题(Concrete    Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。*/
public class ConcreteSubject implements Subject {private List<Observer> observers = new ArrayList<>();@Overridepublic void addObserver(Observer observer){this.observers.add(observer);}@Overridepublic void removeObserver(Observer observer){this.observers.remove(observer);}@Overridepublic void change() {System.out.println("subject is changed..........");observers.forEach(Observer::update);}
}

2. 通过JDK提供的接口实现观察者模式

  • 具体观察者(Concrete Observer),实现java.util.Observer接口

/*** @author FluffyCatkin* @version 1.0* @date 2020/1/7 0007 16:20* @description 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。*/
public class ObserverImplObserver implements Observer {private String name;public ObserverImplObserver(String name) {this.name = name;}@Overridepublic void update(Observable observable, Object arg) {System.out.println("receive......"+name+"is changed.......");System.out.println(arg);}
}
  • 具体主题(Concrete Subject),实现java.util.Observable接口
/*** @author FluffyCatkin* @version 1.0* @date 2020/1/7 0007 16:19* @description 具体主题(Concrete    Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。*/
public class SubjectExtendsObservable extends Observable {private String state;public SubjectExtendsObservable(String state) {this.state = state;}public void setState(String state) {super.setChanged();super.notifyObservers("arg........subject to  observer");this.state = state;}
}

3. 测试类


/*** @author FluffyCatkin* @version 1.0* @date 2020/1/7 0007 15:57* @description 观察者模式**在现实世界中,许多对象并不是独立存在的,其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变。例如,某种商品的物价上涨时会导致部分商家高兴,而消费者伤心;还有,当我们开车到交叉路口时,遇到红灯会停,遇到绿灯会行。这样的例子还有很多,例如,股票价格与股民、微信公众号与微信用户、气象局的天气预报与听众、小偷与警察等。** 在软件世界也是这样,例如,Excel 中的数据与折线图、饼状图、柱状图之间的关系;MVC 模式中的模型与视图的关系;事件模型中的事件源与事件处理者。所有这些,如果用观察者模式来实现就非常方便。* 模式的定义与特点:* 观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。** 观察者模式是一种对象行为型模式,其主要优点如下:* 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。* 目标与观察者之间建立了一套触发机制。** 它的主要缺点如下:* 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。* 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。* 模式的结构与实现:* 实现观察者模式时要注意具体目标对象和具体观察者对象之间不能直接调用,否则将使两者之间紧密耦合起来,这违反了面向对象的设计原则。* 1. 模式的结构* 观察者模式的主要角色如下。抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。* 具体主题(Concrete    Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。* 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。* 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。* 模式的应用场景:* 通过前面的分析与应用实例可知观察者模式适合以下几种情形。对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。* 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时,可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。**/
public class Main {/*** 测试观察者模式*/@Testpublic void observerTest(){Subject subject = new ConcreteSubject();subject.addObserver(new ConcreteObserver("observer1......................"));subject.addObserver(new ConcreteObserver("observer2......................"));subject.change();}/*** 通过  Observable  Observer 实现观察者模式*/@Testpublic void observableTest(){SubjectExtendsObservable observable = new SubjectExtendsObservable("state1");observable.addObserver(new ObserverImplObserver("observer1......"));observable.addObserver(new ObserverImplObserver("observer2......"));observable.setState("state2");}
}

自定义接口实现观察者模式运行结果:


subject is changed..........
receive......observer1......................is changed.......
receive......observer2......................is changed.......

通过 Observable Observer 实现观察者模式运行结果:


receive......observer2......is changed.......
arg........subject to  observer
receive......observer1......is changed.......
arg........subject to  observer

三、应用场景

  观察者模式适合以下几种情形:

  • 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
  • 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时,可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
  • 实现类似广播机制的功能,不需要知道具体收听者,只需分发广播,系统中感兴趣的对象会自动接收该广播。
  • 多层级嵌套使用,形成一种链式触发机制,使得事件具备跨域(跨越两种观察者类型)通知。

四、优缺点分析

  其主要优点如下:

  • 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
  • 目标与观察者之间建立了一套触发机制。

  它的主要缺点如下:

  • 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
  • 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

代码地址:https://gitee.com/fluffycatkin/JavaDesignModel.git

image.png

原文出处:http://c.biancheng.net/view/1390.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/60335.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2007-2022年上市公司污染排放数据/2007-2022年上市公司污染排放水平、污染排放量数据

2007-2022年上市公司污染排放数据/2007-2022年上市公司污染排放水平、污染排放量数据 1、时间&#xff1a;2007-2022年 2、指标&#xff1a;证券代码、year、化学需氧量、氨氮排放量、总氮、总磷、水体综合污染当量对数、二氧化硫、氮氧化物、烟尘、空气综合污染当量对数、总…

代码中的3种错误-思考及应对方法

我们聊到了代码中的3中错误。今天我想在具体的代码上讨论如何应对这3中错误。 这段代码很普通&#xff0c;就是在浏览器中自动下载文件&#xff0c;代码如下&#xff1a; const link document.createElement(a) link.href dataUrl link.download output.png link.click()这…

静态类方法的同步

由于在调用静态方法时&#xff0c;对象实例不一定被创建。因此&#xff0c;就不能使用this来同步静态方法&#xff0c;而必须使用Class对象来同步静态方法。代码如下&#xff1a; 通过synchronized块同步静态方法 public class StaticSyncBlock { public static void…

还只是听说过Generator函数?那就来全面了解它吧

Generator函数 基本概念 Generator函数时ES6提供的一种异步编程解决方案&#xff1b; 一、语法上&#xff1a; 可以理解为一个状态机&#xff0c;封装了多个内部状态执行Generator函数会返回一个遍历器对象 二、形式上的特点&#xff1a; function命令和函数名之间有一个…

word表格左侧边线明明有,但却不显示

如题&#xff0c;解决方法&#xff1a; 方案一&#xff1a; 1&#xff09;选中表格 2&#xff09;布局菜单--->自动调整 3&#xff09;自动调整中&#xff0c;选择“根据窗口自动调整表格” 4&#xff09;表格左侧边线就显示出来了。 方案二&#xff1a;把表格粘贴到新…

Kubernetes技术--Kubernetes架构组件以及核心概念

1.Kubernetes集群架构组件 搭建一个Kubernetes环境集群,其架构如下所示: 内容详解: Master:控制节点,指派任务、决策 Node:工作节点,实际干活的。 Master组件内容:

国产芯片设备达到3纳米,还打入台积电,美日荷被彻底赶出市场

由于众所周知的原因&#xff0c;荷兰和日本的光刻机对中国供应面临限制&#xff0c;其他芯片设备和材料也受到很大的限制&#xff0c;这促使国产芯片产业链积极完善&#xff0c;以实现纯国产芯片工艺&#xff0c;虽然在光刻机方面还稍微落后&#xff0c;不过有一项国产芯片设备…

day-03 基于TCP的服务器端/客户端

一.理解TCP和UDP TCP&#xff08;Transmission Control Protocol&#xff09;和UDP&#xff08;User Datagram Protocol&#xff09;是两种常见的传输层协议&#xff0c;用于在计算机网络中提供可靠的数据传输。 1.TCP&#xff1a; 连接导向&#xff1a;TCP是一种面向连接的…

Android深思如何防止快速点击

前言 其实快速点击是个很好解决的问题&#xff0c;但是如何优雅的去解决确是一个难题&#xff0c;本文主要是记录一些本人通过解决快速点击的过程中脑海里浮现的一些对这个问题的深思。 作者&#xff1a;流浪汉kylin 链接&#xff1a;https://juejin.cn/post/7197337416096055…

Cookie中的SameSite标示是什么

目录 背景介绍 原理 MDN上有比较完整的描述 如何确定cookie是否已经设置相关属性 背景介绍 SameSit

Numerical Calculation 数值计算

Numerical Calculation 数值计算 数值计算第一次实验(C语言版) C语言编程常用数值计算的高性能实现 /* 高位全0&#xff0c;低N位全1 */ #define Low_N_Bits_One(N) ((1<<N) -1)/* 高位全1&#xff0c;低N位全0 */ #define Low_N_Bits_Zero(N) (~((1<<N)…

Mac 卸载 PyCharm 方法

Mac 系统下 PyCharm 没有一键卸载程序&#xff0c;也没有完全卸载的插件&#xff0c;若要彻底删除&#xff0c;除了在应用&#xff08;Application&#xff09;里删除 PyCharm 到垃圾桶外&#xff0c;还需要在终端&#xff08;Terminal&#xff09;执行删除相应的文件及文件夹。…

vue3+ts封装弹窗,分页封装

定义defaultDialog .vue <script lang"ts" setup> import { ref,toRefs,onUpdated } from vue import { ElMessageBox } from element-plus const props defineProps({//接收参数&#xff0c;父组件传的时候用:msg123的形式msg:String,show:{type:Boolean,defa…

Cesium Entity、dataSource添加与删除

Cesium Entity、dataSource添加与删除 一、Entity1. 添加实体2. 获取实体3. 删除实体 二、dataSource1. 添加数据源&#xff1a;2. 删除数据源 一、Entity 在Cesium中&#xff0c;要添加和删除实体和数据源可以使用以下代码&#xff1a; 1. 添加实体 var entity viewer.ent…

c++ qt--线程(一)(第八部分)

c qt–线程&#xff08;一&#xff09;&#xff08;第八部分&#xff09; 一.进程&#xff08;Process&#xff09; 在任务管理器中的进程页下&#xff0c;可以看到进程&#xff0c;任务管理器将进程分为了三类&#xff0c;应用、后台进程、window进程 应用&#xff1a; 打开…

针对java中list.parallelStream()的多线程数据安全问题我们采用什么方法最好呢?

当使用List.parallelStream()方法进行多线程处理时&#xff0c;可能会涉及到数据安全问题。下面是一些常见的方法来处理parallelStream()的多线程数据安全问题&#xff1a; 1. 使用线程安全的集合&#xff1a;Java中提供了线程安全的集合类&#xff0c;如CopyOnWriteArrayList…

Docker(三) 创建Docker镜像

一、在Docker中拉取最基本的Ubuntu系统镜像 搜索Ubuntu镜像 Explore Dockers Container Image Repository | Docker Hub 下载镜像 docker pull ubuntu:22.04 二、在镜像中添加自己的内容 使用ubuntu镜像创建容器 docker run -it ubuntu:20.04 /bin/bash 在容器中创建了一个文…

【高性能计算】opencl语法及相关概念(二):索引,队列,核函数

目录 数据并行及任务并行异构编程语言的共性opencl的划分方式opencl上下文定义以字符串为主的程序对象同一设备&#xff0c;多个命令队列同时执行多个核函数的示例 数据并行及任务并行 数据并行是将大规模的计算任务划分为多个子任务&#xff0c;并将这些子任务同时应用于不同…

Android AGP版本

做个记录&#xff1a; Android AGP版本 https://developer.android.com/studio/releases/gradle-plugin?hlzh-cn

Android动态可编辑长度列表

概述 在界面实现一个列表&#xff0c;用户可以随意给列表新增或者删除项目&#xff0c;在开发中比较常用&#xff0c;但是真正做起来又有点花时间&#xff0c;今天花时间做一个&#xff0c;以便在以后的开发中用到。 详细 运行效果&#xff1a; 二、实现思路&#xff1a; 1…