设计模式详解---观察者模式

news2024/12/26 0:12:23

1. 观察者模式简介

1.1. 什么是观察者模式

观察者模式是一种行为型设计模式,用于建立对象之间的一对多依赖关系。在该模式中,一个被称为主题(Subject)的对象维护一组观察者(Observer),并在其状态发生变化时自动通知观察者。这样,观察者对象可以及时获取主题对象的最新状态并执行相应的操作。

1.2. 观察者模式涉及的角色

主题(Subject):被观察的对象,维护一组观察者并提供注册、删除和通知观察者的方法。
观察者(Observer):接收主题通知的对象,定义了一个更新方法,在接收到通知时执行相应的操作。
具体主题(Concrete Subject):具体的主题实现类,继承或实现主题接口,并在状态变化时通知观察者。
具体观察者(Concrete Observer):具体的观察者实现类,实现观察者接口,并在收到通知时执行具体的操作。

1.3. 观察者模式的工作原理

主题对象维护一个观察者列表,该列表存储了所有订阅主题通知的观察者对象。当主题对象的状态发生变化时,它会遍历观察者列表,并调用每个观察者对象的更新方法,将新的状态传递给观察者。观察者对象接收到主题的通知后,执行相应的操作,以便响应状态的变化。

1.4. 观察者模式的优点

解耦性:主题和观察者之间是松耦合的,它们之间通过抽象的接口进行通信,使得它们可以独立地进行修改和扩展。

可扩展性:可以方便地增加新的观察者,而无需修改主题的代码。

随时更新:主题状态变化时,观察者能够立即得到通知并进行相应的操作。

规范性:观察者模式定义了主题和观察者之间的一套规范,使得代码更具可读性和可维护性。

2. 代码实现

代码实现最好自己手写一遍,有利于更加理解观察者模式:

2.1.主题接口 Subject

        首先,定义一个主题接口 Subject,其中包含三个方法:registerObserver() 用于注册观察者,removeObserver() 用于移除观察者,notifyObservers() 用于通知观察者:

package DesignPattern.observerMode;

/**
 * @Author: stukk
 * @Description: 主题接口
 * @DateTime: 2023-12-13 22:13
 **/
public interface Subject {

    void registerObServer(Observer obServer);
    void removeObServer(Observer obServer);
    void notifyObServer();

}
2.2. 具体主题类 ConcreteSubject

        然后,实现一个具体主题类 ConcreteSubject,它维护一个观察者列表,并在状态变化时通知观察者。

package DesignPattern.observerMode.Impl;

import DesignPattern.observerMode.Observer;
import DesignPattern.observerMode.Subject;

import java.util.LinkedList;
import java.util.List;

/**
 * @Author: stukk
 * @Description: 主题接口实现类
 * @DateTime: 2023-12-13 22:14
 **/
public class ConcreteSubject implements Subject {

    private List<Observer> obServers = new LinkedList<>(); //存储观察者
    private int state; //观察对象


    public void setState(int state) {
        this.state = state;
        notifyObServer();
    }

    @Override
    public void registerObServer(Observer obServer) {
        obServers.add(obServer);
    }

    @Override
    public void removeObServer(Observer obServer) {
        obServers.remove(obServer);
    }


    @Override
    public void notifyObServer() { //通知观察者们
        obServers.forEach(obServer -> {
            obServer.update(state);
        });
    }
}
2.3. 观察者接口 ObServer

        接下来,定义一个观察者接口 ObServer,其中包含一个 update() 方法,用于接收和处理主题的通知。

package DesignPattern.observerMode;

/**
 * @Author: stukk
 * @Description: 观察者接口
 * @DateTime: 2023-12-13 22:11
 **/
public interface Observer {
    void update(int state);
}
2.4. 具体观察者类ConcreteObServer

        实现一个具体观察者类 ConcreteObServer,它实现了 Observer 接口,并在收到通知时输出状态信息。

package DesignPattern.observerMode.Impl;

import DesignPattern.observerMode.Observer;

/**
 * @Author: stukk
 * @Description: 观察者接口实现类
 * @DateTime: 2023-12-13 22:12
 **/
public class ConcreteObserver implements Observer {

    private String name;  //观察者的名字

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(int state) {
        System.out.println(name + "接收到了更新请求,新的状态:" +state );
    }
}
2.5. 测试观察者模式

        最后我们写一个类来测试观察者的功能

package DesignPattern.observerMode;

import DesignPattern.observerMode.Impl.ConcreteObserver;
import DesignPattern.observerMode.Impl.ConcreteSubject;

/**
 * @Author: stukk
 * @Description: 测试观察者模式
 * @DateTime: 2023-12-13 22:24
 **/
public class ObserverModeExample {

    public static void main(String[] args) {
//        主题
        ConcreteSubject subject = new ConcreteSubject();

        Observer obServer1 = new ConcreteObserver("观察者1号");
        Observer obServer2 = new ConcreteObserver("观察者2号");
        Observer obServer3 = new ConcreteObserver("观察者3号");

//        注册观察者
        subject.registerObServer(obServer1);
        subject.registerObServer(obServer2);
        subject.registerObServer(obServer3);

        subject.setState(1);

//        删除2再试试
        subject.removeObServer(obServer2);

        subject.setState(2);


    }

}

最后输出:

3. 观察者模式的应用场景

  1. 当一个对象的状态变化需要通知其他多个对象,并且这些对象的更新行为可能不同的时候:例如,当一个订单状态发生变化时,需要通知多个观察者,如库存管理系统、物流系统和消息通知系统等。

  2. 当存在一对多的依赖关系,一个对象的变化会引起其他多个对象的变化的时候:例如,当一个博客发表新文章时,订阅该博客的多个读者都会收到通知并更新自己的阅读列表。

  3. 当需要将关注点分离,使得主题和观察者之间解耦的时候:主题只需要知道观察者接口,而不需要了解具体的观察者实现。这样可以提高代码的灵活性和可扩展性。

  4. 当系统需要动态地将观察者添加到或移除出主题中的时候:通过动态注册和移除观察者,可以在运行时灵活地管理观察者集合。

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

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

相关文章

Kafka-快速实战

Kafka介绍 ChatGPT对于Apache Kafka的介绍&#xff1a; Apache Kafka是一个分布式流处理平台&#xff0c;最初由LinkedIn开发并于2011年开源。它主要用于解决大规模数据的实时流式处理和数据管道问题。 Kafka是一个分布式的发布-订阅消息系统&#xff0c;可以快速地处理高吞吐…

前端-杂记

1 子域请求时候会默认带上父域下的Coolkie 2 document.cookie 设置cookie只能设置当前域和父域&#xff0c;且path只能是当前页或者/ 比如当前页面地址为 http://localhost:3000/about 我们设置 document.cookie "demo11"; 设置 document.cookie "demo22; …

7.25 SpringBoot项目实战【我的借阅记录】

文章目录 前言一、编写控制器二、编写服务层三、Git提交前言 至此,我们已经实现 图书借阅、收藏、评论等场景,最后来到【还书】场景,首先 还书的 入口 一般 是【我的借阅记录】,在这里可以根据产品设计,对于需要归还的书 操作【还书】,所以本文来实现【我的借阅记录】。…

基于ssm医院住院综合服务管理系统设计与开发论文

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对医院住院信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差…

网站高性能架构设计——高性能数据库集群

从公众号转载&#xff0c;关注微信公众号掌握更多技术动态 --------------------------------------------------------------- 一、高性能数据库简介 1.高性能数据库方式 读写分离&#xff1a;将访问压力分散到集群中的多个节点&#xff0c;没有分散存储压力 分库分表&…

【unity】如何用Unity获取Windows桌面

【背景】 默认的Unity可实现的屏幕共享仅仅针对Unity编辑器的编辑窗口中的Camera展现的内容。本篇研究如何实现用Unity实时反映Windows桌面窗口画面。 【准备插件】 下载地址&#xff1a; https://download.csdn.net/download/weixin_41697242/88623496 将解压后的文件夹直…

排序算法之一:直接插入排序

1.基本思想 直接插入排序是一种简单的插入排序法&#xff0c;其基本思想是&#xff1a; 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到一个新的有序序列 实际中我们玩扑克牌时&#xff0c;就用…

【AI】java,在集合中找最接近给定值的数,且比给定值小

目录 一、最终得到的方案 二、AI辅助找到方案 2.1 【C知道】提供java代码支持 2.2 【文心一言】提供字段翻译支持 一、最终得到的方案 /*** 在 collection 中&#xff0c;找跟 value 最大接近值&#xff0c;且该值小于等于 value** param collection 不为null。* param val…

css 纯样式实现绘出进度条

效果&#xff1a; css代码&#xff1a; .bar{height: 14px;width: 100%;font-size: 10px;margin-top: 5px;background-color: #f5f5f5;}.bar::before{display: block;counter-reset: progress var(--precent); content: ;width: calc(1% * var(--precent));color: #fff;height:…

酸奶店创业新模式,可以轻松应付风险的对策

本人经营一家酸奶店&#xff0c;已经5年时间&#xff0c;也不断学习和探索新的模式&#xff0c;希望我的一些经验可以帮到你。&#xff08;可以点赞收藏&#xff0c;方便以后随时查阅&#xff09; 这几年&#xff0c;各行各业&#xff0c;大家都在说&#xff0c;生意不好做&am…

Qt设置类似于qq登录页面(ikun)

头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QWindow> #include <QIcon> #include <QLabel> #include <QMovie> #include <QLineEdit> #include <QPushButton>QT_BEGIN_NAMESPACE namespace Ui { class…

jemeter,断言:响应断言、Json断言

一、响应断言 接口A请求正常返回值如下&#xff1a; {"status": 10013, "message": "user sign timeout"} 在该接口下创建【响应断言】元件&#xff0c;配置如下&#xff1a; 若断言成功&#xff0c;则查看结果树的接口显示绿色&#xff0c;若…

新版Spring Security6.2案例 - Basic HTTP Authentication

前言&#xff1a; 书接上文&#xff0c;翻译官网Authentication的Username/Password这页&#xff0c;接下来继续翻译basic的这页&#xff0c;因为官网说的都是原理性的&#xff0c;这边一个小案例关于basic http authentication。 Basic Authentication 本节介绍 HTTP 基本身…

C语言union联合体(共用体)

一、定义 联合体&#xff08;共用体&#xff09;是一种特殊的自定义的数据类型&#xff0c;它包含一系列的成员变量&#xff0c;这些成员变量共用一块内存空间。 语法&#xff1a; union 标识符 { data_type 标识符1; data_type 标识符2; . . . dat…

电影推荐系统

基于springboot vue实现的电影推荐系统&#xff0c;通过Jsoup数据爬取。 效果图如下&#xff1a;

Java01 169-184

数组添加 import java.util.Scanner; public class ArrayAdd02 {public static void main(String[] args) {Scanner myScanner new Scanner(System.in);//数组一旦定义&#xff0c;不可以增加&#xff0c;必须增加新的数组int[] arr {1, 2, 3};do {int[] arrNew new int[arr…

2023年【G3锅炉水处理】免费试题及G3锅炉水处理模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年【G3锅炉水处理】免费试题及G3锅炉水处理模拟试题&#xff0c;包含G3锅炉水处理免费试题答案和解析及G3锅炉水处理模拟试题练习。安全生产模拟考试一点通结合国家G3锅炉水处理考试最新大纲及G3锅炉水处理考试真…

目标检测DOTA数据集提取感兴趣类别数据

DOTA数据集 DOTA数据集包含2806张航空图像&#xff0c;尺寸大约从800x800到4000x4000不等&#xff0c;包含15个类别共计188282个实例。其标注方式为四点确定的任意形状和方向的四边形&#xff08;区别于传统的对边平行bbox&#xff09;。类别分别为&#xff1a;plane, ship, s…

20、备忘录模式(Memento Pattern,不常用)

备忘录模式又叫作快照模式&#xff0c;该模式将当前对象的内部状态保存到备忘录中&#xff0c;以便在需要时能将该对象的状态恢复到原先保存的状态。 备忘录模式提供了一种保存和恢复状态的机制&#xff0c;常用于快照的记录和状态的存储&#xff0c;在系统发生故障或数据发生…

为什么QLC NAND才是ZNS SSD最大的赢家?-part2

ZNS出现的背景是什么&#xff1f;ZNS SSD的原理是把namespace空间划分多个zone空间&#xff0c;zone空间内部执行顺序读写。 在ZNS的场景下&#xff0c;不同应用按照Zone配置信息&#xff0c;相应存放业务数据。由于是Host管理数据的摆放和存取位置&#xff0c;会最大程度减少G…