二十、观察者模式

news2024/10/6 20:35:39

一、什么是观察者模式

  观察者(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;
    }

    @Override
    public 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<>();

    @Override
    public void addObserver(Observer observer){
        this.observers.add(observer);
    }
    @Override
    public void removeObserver(Observer observer){
        this.observers.remove(observer);
    }
    @Override
    public 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;
    }
    @Override
    public 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 {
    /**
     * 测试观察者模式
     */
    @Test
    public void observerTest(){
        Subject subject = new ConcreteSubject();
        subject.addObserver(new ConcreteObserver("observer1......................"));
        subject.addObserver(new ConcreteObserver("observer2......................"));

        subject.change();
    }

    /**
     * 通过  Observable  Observer 实现观察者模式
     */
    @Test
    public 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.coloradmin.cn/o/952203.html

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

相关文章

苹果秋季发布会,北京时间9月13日

苹果公司宣布&#xff0c;将于当地时间9月12日&#xff08;北京时间9月13日&#xff09;召开新闻发布会&#xff0c;发布会将于美东时间下午1点&#xff08;北京时间凌晨1点&#xff09;在苹果官网上进行直播&#xff0c;预计苹果届时将在会上发布iPhone 15系列和新款苹果手表。…

如何制作并运行 jar 程序

以下是用 Intellij 制作 jar 程序&#xff0c;并运行的方法。 【1】新建工程&#xff0c;保持默认选项&#xff0c;Next 【2】保持默认选项&#xff0c;Next 【3】给工程命名&#xff0c;设置保存位置&#xff0c;Finish 【4】新建工程结束&#xff0c;进入开发界面 【5】展开…

Spring源码分析(七)不同作用域下Bean的创建

目录 1.1 单例模式的实例化1.1.1 从缓存中获取1.1.2 前置处理1.1.3 获取Bean1.1.4 后置处理1.1.5 加入缓存 1.2 原型模式实例化1.3 其他模式实例化 官网&#xff1a;Home参考书籍&#xff1a;Spring源码深度解析-郝佳编著-微信读书 上一篇文章我们分析到不同的作用域创建Bean&…

推荐两款开源的绘制流程图软件

一句话导读 目前流程图绘制软件非常多&#xff0c;包括本机安装的、web端的都有&#xff0c;如Visio、Graphviz、processOn等等。但是几乎都是收费的。本文给大家介绍两款优秀的开源免费的流程图绘制软件。 目录 一句话导读 一、draw.io 二、Meta2d.js ​1.为什么使用 2.…

权限提升-PostgreSQL数据库提权+第三方应用提权

权限提升基础信息 1、具体有哪些权限需要我们了解掌握的&#xff1f; 后台权限&#xff0c;网站权限&#xff0c;数据库权限&#xff0c;接口权限&#xff0c;系统权限&#xff0c;域控权限等 2、以上常见权限获取方法简要归类说明&#xff1f; 后台权限&#xff1a;SQL注入,数…

关于两个不同数据库的两张表建立数据库链接,关联查询数据

一、数据库链接 数据库链接&#xff08;database link&#xff09;是用于跨不同数据库之间进行连接和数据传输的工具或方法。它允许在一个数据库中访问另一个数据库中的对象和数据。 二、具体操作 以Oracle数据库为例 --1.建立链接tjpt CREATE DATABASE LINK tjpt CONNECT…

STM32G0 定时器PWM DMA输出驱动WS2812配置 LL库

通过DMA方式输出PWM模拟LED数据信号 优点&#xff1a;不消耗CPU资源 缺点&#xff1a;占用内存较大 STM32CUBEMX配置 定时器配置 定时器通道&#xff1a;TIM3 CH2 分频&#xff1a;0 重装值&#xff1a;79&#xff0c;芯片主频64Mhz&#xff0c;因此PWM输出频率&#xff1a…

mall :rabbit项目源码解析

文章目录 一、mall开源项目1.1 来源1.2 项目转移1.3 项目克隆 二、RabbitMQ 消息中间件2.1 rabbit简介2.2 分布式后端项目的使用流程2.3 分布式后端项目的使用场景 三、安装RabbitMQ(Win10)3.1安装erLang语言&#xff0c;配置环境变量3.2 安装RabbitMQ服务端3.3 测试安装效果 四…

webservice调用对接第三方系统

#webservice调用对接第三方系统# 最近接到一个任务&#xff0c;需要对接第三方数据&#xff0c;第三方提供对接方式的是通过webservice调用&#xff0c;webservice调用有好几种方式&#xff0c;具体可以自行了解&#xff0c;我选择的是通过wsdl文件自动生成客户端代码对接。 …

专门针对开发人员,攻击者利用Rust获取操作系统信息

近日&#xff0c;研究人员在 Rust 编程语言的 crate 注册表中发现了一些恶意软件包&#xff0c;专门针对开发人员。 Phylum 在上周发布的一份报告中称&#xff0c;这些库是由一个名为 "amaperf "的用户在 2023 年 8 月 14 日至 16 日之间上传的。现已删除的软件包名…

2461. 长度为 K 子数组中的最大和

2461. 长度为 K 子数组中的最大和 C代码&#xff1a;滑动窗口 long long maximumSubarraySum(int* nums, int numsSize, int k){int hash[100001] {0};long long sum 0;int l 0;long long ans 0;for (int r 0; r < numsSize; r) {hash[nums[r]];sum nums[r];while ((…

ZooKeeper基础命令和Java客户端操作

1、zkCli的常用命令操作 &#xff08;1&#xff09;Help &#xff08;2&#xff09;ls 使用 ls 命令来查看当前znode中所包含的内容 &#xff08;3&#xff09;ls2查看当前节点数据并能看到更新次数等数据 &#xff08;4&#xff09;stat查看节点状态 &#xff08;5&#xf…

【Unity-Cinemachine相机】Cinemachine Brain属性详解

在Package Manager中下载Cinemachine 创建一个Virtual Camera&#xff0c;然后会发现Main Camera后面多出了个标志&#xff0c;而且属性也不能再修改了 因为绑定了CinemachineBrain&#xff0c;它会读取场景中某个虚拟相机的配置&#xff0c;并以此配置来控制相机的行为&#x…

C#---第二十:不同类型方法的执行顺序(new / virtual / common / override)

本文介绍不同类型的方法&#xff0c;在代码中的执行顺序问题&#xff1a; 构造方法普通方法&#xff08;暂用common代替&#xff09;、虚方法&#xff08;Virtual修饰&#xff09;、New方法&#xff08;new修饰&#xff09;三个优先级相同overide方法&#xff08;会替换virtual…

Docker 中下载各版本的 CentOS、CentOS Steam 方式

如果你跟我一样&#xff0c;想要在docker下载centos的镜像&#xff0c;但是无奈访问不了 https://hub.docker.com/&#xff0c;于是不知道有哪些tag可以下载&#xff0c;该如何办呢&#xff1f; 方法如下&#xff0c;以供参考。 访问&#xff1a;https://quay.io/repository/…

【Terraform学习】Terraform模块基础操作(Terraform模块)

本站以分享各种运维经验和运维所需要的技能为主 《python》&#xff1a;python零基础入门学习 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8》暂未更新 《docker学习》暂未更新 《ceph学习》ceph日常问题解…

Python 及 Pycharm 的安装 2023.8

Python 及 PyCharm 的安装 仅适用于 Windows 系统&#xff01; 视频教程&#xff1a;【Python及Pycharm的安装 2023.8】 https://www.bilibili.com/video/BV1A34y1T7Gu 文章目录 Python 及 PyCharm 的安装安装 Python安装 PyCharmHi, PyCharmPyCharm 汉化 安装 Python 进入 …

Linux音频了解

ALPHA I.MX6U 开发板支持音频&#xff0c;板上搭载了音频编解码芯片 WM8960&#xff0c;支持播放以及录音功能&#xff01; 本章将会讨论如下主题内容。 ⚫ Linux 下 ALSA 框架概述&#xff1b; ⚫ alsa-lib 库介绍&#xff1b; ⚫ alsa-lib 库移植&#xff1b; ⚫ alsa-l…

8.30 QT界面 常用组件 和 类的 设置

this -> setFixedSize(540, 410); //固定窗口大小this -> setWindowTitle("啊啊啊"); //设置窗口标题this -> setWindowIcon(QIcon("E:/1.png")); //设置窗口图标QLabel *lab1 new QLabel(this); //构造一个标签lab1 -> setPixmap(QPi…

Doris数据库BE——Stream load流程中事务状态

Stream Load的事务管理由FE负责&#xff0c;Doris的事务状态包括&#xff1a;PREPARE、COMMITTED、VISIBLE和ABORTED。 数据导入开始之前&#xff0c;Coordinator BE节点会向FE发送Begin Transaction请求&#xff0c;FE会为当前label开启一个新的事务&#xff0c;并为事务分配…