Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >事件监听机制

事件监听机制

作者头像
wangweijun
发布于 2022-06-02 09:50:35
发布于 2022-06-02 09:50:35
8.6K00
代码可运行
举报
文章被收录于专栏:wangweijunwangweijun
运行总次数:0
代码可运行

相信大家都学过Java中的GUI,不知道你们对GUI中的事件机制有没有产生过好奇心,当我们点击按钮时,就可以触发对应的点击事件,这一过程究竟是如何实现的呢?本篇文章我们就来聊一聊Java中的事件监听机制。

在了解事件监听机制之前,我们先来学习一个设计模式——观察者模式,事件监听机制的原理就是它。

场景设置

假设现在有一个需求,你正在运营一个有关天气的接口,要求是可以将天气信息推送出去,前提是接入了该接口的开发者才能收到天气信息,该如何实现呢?

首先我们来创建一个类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.wwj.spring.guanchazhe;

/**
 * 显示天气信息
 */
public class PushWeather {

    private int temperature;
    private int humidity;
    private int airPressure;

    public void update(int temperature, int humidity, int airPressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.airPressure = airPressure;
        show();
    }

    public void show() {
        System.out.print("温度:" + temperature + "\t");
        System.out.print("湿度:" + humidity + "\t");
        System.out.print("气压:" + airPressure + "\t");
        System.out.println();
    }
}

该类模拟的是第三方开发者接入我们的数据接口,显示天气信息,其中成员属性分别为温度、湿度和气压,并提供update方法用于更新数据(该方法是由其它类调用的)。

继续创建一个类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class WeatherDataInterface {

    private int temperature;
    private int humidity;
    private int airPressure;
    private PushWeather pushWeather;

    public WeatherDataInterface(PushWeather pushWeather) {
        this.pushWeather = pushWeather;
    }

    public void update() {
        pushWeather.update(temperature, humidity, airPressure);
    }

    public void updateWeatherData(int temperature, int humidity, int airPressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.airPressure = airPressure;
        update();
    }
}

该类就是天气数据接口类,类中包含了第三方开发者PushWeather,当我们调用updateWeatherData更新接口中的天气信息时,它会同步调用第三方开发者的update方法实现数据同步,下面我们就来试一试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Main {

    public static void main(String[] args) {
        PushWeather pushWeather = new PushWeather();
        WeatherDataInterface wdi = new WeatherDataInterface(pushWeather);
        wdi.updateWeatherData(10, 20, 30);
        System.out.println("更新天气数据");
        wdi.updateWeatherData(20, 30, 40);
    }
}

运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
温度:10	湿度:20	气压:30	
更新天气数据
温度:20	湿度:30	气压:40	

这种实现方式是有很大弊端的,因为如果又有一个第三方开发者要接入你的接口,那么修改的代码将会非常多,不信来看看,首先创建第三方开发者:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Baidu {

    private int temperature;
    private int humidity;
    private int airPressure;

    public void update(int temperature, int humidity, int airPressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.airPressure = airPressure;
        show();
    }

    public void show() {
        System.out.print("百度接入————温度:" + temperature + "\t");
        System.out.print("百度接入————湿度:" + humidity + "\t");
        System.out.print("百度接入————气压:" + airPressure + "\t");
        System.out.println();
    }
}

然后需要修改的是我们的天气数据接口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class WeatherDataInterface {

    private int temperature;
    private int humidity;
    private int airPressure;
    private PushWeather pushWeather;
    private Baidu baidu;

    public WeatherDataInterface(PushWeather pushWeather,Baidu baidu) {
        this.pushWeather = pushWeather;
        this.baidu = baidu;
    }

    public void update() {
        pushWeather.update(temperature, humidity, airPressure);
        baidu.update(temperature,humidity,airPressure);
    }

    public void updateWeatherData(int temperature, int humidity, int airPressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.airPressure = airPressure;
        update();
    }
}

首先需要添加百度到成员变量,然后修改构造方法, 还需要修改update方法,让其也能更新百度的数据,测试代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Main {

    public static void main(String[] args) {
        PushWeather pushWeather = new PushWeather();
        Baidu baidu = new Baidu();
        WeatherDataInterface wdi = new WeatherDataInterface(pushWeather,baidu);
        wdi.updateWeatherData(10, 20, 30);
        System.out.println("更新天气数据");
        wdi.updateWeatherData(20, 30, 40);
    }
}

运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
温度:10	湿度:20	气压:30	
百度接入————温度:10	百度接入————湿度:20	百度接入————气压:30	
更新天气数据
温度:20	湿度:30	气压:40	
百度接入————温度:20	百度接入————湿度:30	百度接入————气压:40	

观察者模式

观察者模式,又被称为发布——订阅模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当该主题对象发生数据变化时,会通知所有的观察者对象更新数据。

很显然,在刚才的案例中,第三方开发者就是观察者模式中的观察者,而天气数据接口就是主题对象,当天气数据接口发生变化时,就会通知那些依赖于天气接口的观察者去更新自己的数据,所以刚才的案例是非常适合使用观察者模式来进行改造的,那怎么实现呢?

观察者模式中有几个非常重要的概念:

  1. Subject:抽象主题,它是用于抽象观察者的,因为主题对象需要管理所有依赖于它的观察者,所以必须对观察者抽象,才能实现统一的管理,提供接口注册和注销观察者
  2. ConcreteSubject:具体主题,它用于具体实现主题对象,它会将有关状态存入具体的观察者对象,在具体主题数据发生变化时,会给所有已经注册的观察者发送通知
  3. Observer:抽象观察者,它定义了一个接口,用于对观察者进行抽象
  4. ConcreteObserver:具体观察者,实现抽象观察者接口,以便在得到主题对象的通知时更新自身数据

\

现在我们就来改造刚才的案例,首先创建抽象主题:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Subject {

    // 注册观察者对象
    void register(Observer observer);

    // 移除观察者对象
    void remove(Observer observer);

    // 通知所有观察者更新数据
    void notify(int temperature, int humidity, int airPressure);
}

然后创建抽象观察者:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Observer {

    // 更新天气数据
    void update(int temperature, int humidity, int airPressure);
}

接着具体实现主题:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class WeatherDataSubject implements Subject {

    // 管理所有观察者
    private Vector<Observer> vector;

    public WeatherDataSubject() {
        vector = new Vector<>();
    }

    @Override
    public void register(Observer observer) {
        vector.add(observer);
    }

    @Override
    public void remove(Observer observer) {
        vector.remove(observer);
    }

    @Override
    public void notify(int temperature, int humidity, int airPressure) {
        for (Observer observer : vector) {
            observer.update(temperature, humidity, airPressure);
        }
    }
}

最后就是创建具体的观察者,也就是第三方开发者:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Baidu implements Observer {

    private int temperature;
    private int humidity;
    private int airPressure;

    public void show() {
        System.out.print("百度接入————温度:" + temperature + "\t");
        System.out.print("百度接入————湿度:" + humidity + "\t");
        System.out.print("百度接入————气压:" + airPressure + "\t");
        System.out.println();
    }

    @Override
    public void update(int temperature, int humidity, int airPressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.airPressure = airPressure;
        show();
    }
}

编写测试代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Main {

    public static void main(String[] args) {
        Baidu baidu = new Baidu();
        WeatherDataSubject subject = new WeatherDataSubject();
        subject.register(baidu);
        subject.notify(10, 20, 30);
        System.out.println("更新天气数据");
        subject.notify(20, 30, 40);
    }
}

运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
百度接入————温度:10	百度接入————湿度:20	百度接入————气压:30	
更新天气数据
百度接入————温度:20	百度接入————湿度:30	百度接入————气压:40	

现在若是想接入新的第三方开发者,那就变得非常简单了,首先创建新的开发者:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Alibaba implements Observer {
    private int temperature;
    private int humidity;
    private int airPressure;

    public void show() {
        System.out.print("阿里巴巴接入————温度:" + temperature + "\t");
        System.out.print("阿里巴巴接入————湿度:" + humidity + "\t");
        System.out.print("阿里巴巴接入————气压:" + airPressure + "\t");
        System.out.println();
    }

    @Override
    public void update(int temperature, int humidity, int airPressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.airPressure = airPressure;
        show();
    }
}

然后修改测试代码即可:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Main {

    public static void main(String[] args) {
        Baidu baidu = new Baidu();
        Alibaba alibaba = new Alibaba();
        WeatherDataSubject subject = new WeatherDataSubject();
        subject.register(baidu);
        subject.register(alibaba);
        subject.notify(10, 20, 30);
        System.out.println("更新天气数据");
        subject.notify(20, 30, 40);
    }
}

运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
百度接入————温度:10	百度接入————湿度:20	百度接入————气压:30	
阿里巴巴接入————温度:10	阿里巴巴接入————湿度:20	阿里巴巴接入————气压:30	
更新天气数据
百度接入————温度:20	百度接入————湿度:30	百度接入————气压:40	
阿里巴巴接入————温度:20	阿里巴巴接入————湿度:30	阿里巴巴接入————气压:40

通过观察者模式极大地解除了程序间的耦合,虽然主题对象中仍然依赖了一个集合类型,但它已经被抽象化了,所以耦合度其实并不算很高,通过这种方式,我们在接入新的开发者时,只需向主题对象注册即可,若是不想接入了,也可以注销该开发者。

事件监听机制

了解观察者模式之后,我们进入本篇文章的重心,事件监听机制。

在该模型中,有三个非常重要的概念:

  1. 事件
  2. 事件源
  3. 事件监听器

其具体流程是:用户操作(比如点击)导致事件触发,前提是事件监听器已经被注册好了,事件触发后会生成事件对象,此时事件对象会作为参数传递给事件监听器,监听器调用对应的方法进行处理。

\

在这里事件源就是主题对象,而事件监听器就是观察者,当事件源发生变化时,主题对象就会通知所有的观察者处理数据,那么接下来我们就来实现一下。

首先创建事件接口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Event {

    // 事件回调
    void callback();
}

然后创建具体实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ValueEvent implements Event {

    // 事件三要素:事件源、事件发生事件、事件消息
    private Object source;
    private LocalDateTime when;
    private String msg;

    public void setSource(Object source) {
        this.source = source;
    }

    public void setWhen(LocalDateTime when) {
        this.when = when;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getSource() {
        return source;
    }

    public LocalDateTime getWhen() {
        return when;
    }

    public String getMsg() {
        return msg;
    }

    @Override
    public String toString() {
        return "ValueEvent{" +
                "source=" + source +
                ", when=" + when +
                ", msg='" + msg + ''' +
                '}';
    }

    @Override
    public void callback() {
        System.out.println(this);
    }
}

创建监听器接口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface EventListener {

    // 触发事件
    void triggerEvent(Event event);
}

实现监听器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ValueChangeListener implements EventListener {

    @Override
    public void triggerEvent(Event event) {
        // 调用事件回调方法
        event.callback();
    }
}

最后编写事件源接口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface EventSource {

    // 注册监听器
    void addListener(EventListener listener);

    // 通知所有监听器
    void notifyListener();
}

实现事件源接口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class ValueSource implements EventSource {

    // 管理所有监听器
    private Vector<EventListener> listeners;

    private String msg;

    public ValueSource() {
        listeners = new Vector<>();
    }

    @Override
    public void addListener(EventListener listener) {
        listeners.add(listener);
    }

    @Override
    public void notifyListener() {
        for (EventListener listener : listeners) {
            ValueEvent event = new ValueEvent();
            event.setSource(this);
            event.setWhen(LocalDateTime.now());
            event.setMsg("更新数据:" + msg);
        }
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
        notifyListener();
    }
}

编写测试代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Main {

    public static void main(String[] args) {
        ValueSource source = new ValueSource();
        source.addListener(new ValueChangeListener());
        source.setMsg("50");
    }
}

运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ValueEvent{source=com.wwj.spring.guanchazhe.click.ValueSource@1d81eb93, when=2021-05-22T13:19:26.806, msg='更新数据:50'}

我们来仔细分析一下这个过程,首先我们创建了一个事件源:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ValueSource source = new ValueSource();

它相当于观察者模式中的主题对象,也就是被观察者,当被观察者数据发生变化时,通知所有监听器进行处理,所以我们为其注册了一个监听器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
source.addListener(new ValueChangeListener());

此时我们修改事件源的数据:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
source.setMsg("50");

就会执行setMsg方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void setMsg(String msg) {
    this.msg = msg;
    notifyListener();
}

该方法又调用了notifyListener方法,通知所有监听器处理:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void notifyListener() {
    for (EventListener listener : listeners) {
        ValueEvent event = new ValueEvent();
        event.setSource(this);
        event.setWhen(LocalDateTime.now());
        event.setMsg("更新数据:" + msg);
        listener.triggerEvent(event);
    }
}

在该方法中,首先需要创建事件,并设置事件源,也就是当前对象,设置事件发生时间和消息,最后调用监听器的事件处理方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void triggerEvent(Event event) {
    // 调用事件回调方法
    event.callback();
}

该方法又调用了事件的回调方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void callback() {
    System.out.println(this);
}

事件回调方法就输出了当前对象,以上就是整个事件监听机制的流程。

总结

最后,我们通过这张图,再总结一下事件监听的整个流程:

  1. 首先创建事件源,并为其注册事件
  2. 当调用setMsg方法修改事件源中的数据时,会调用notifyListener方法通知所有监听器
  3. 在notifyListener方法中会遍历所有的监听器,创建事件对象,并作为参数传入监听器的事件处理方法(triggerEvent)
  4. 监听器的triggerEvent方法会调用事件的回调方法(callback)
  5. 回调方法用于编写具体的处理逻辑,比如输出内容给用户反馈
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-06-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java设计模式之观察者模式
案例 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)。 需要设计开放型API,便于其他第三方也能接入气象站获取数据。 提供温度、气压和湿度的接口 测量数据更新时,要能实时的通知给第三方 普通方案 通过getXxx方法,可以让第三方接入,并得到相关信息. 当数据有更新时,气象站通过调用dataChange() 去更新数据,当第三方再次获取时,就能得到最新数据,当然也可以推送。 public class CurrentConditions
shaoshaossm
2022/12/27
2750
Java设计模式之观察者模式
观察者模式上篇
天气更新时候,调用天气对象的dataChange方法,得到数据后,然后将数据通过display()方法展示出来。
凯哥Java
2019/08/23
4090
观察者模式上篇
图解Java设计模式之观察者模式
1)气象站可以将每天测量到的湿度、温度、气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)。 2)需要设计开放型API,便于其他第三方也能接入气象站获取数据。 3)提供温度、气压和湿度的接口。 4)测量数据更新时,要能实时的通知给第三方。
海仔
2020/04/02
4360
图解Java设计模式之观察者模式
观察者模式解读
1) 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)。 2) 需要设计开放型 API,便于其他第三方也能接入气象站获取数据。 3) 提供温度、气压和湿度的接口 4) 测量数据更新时,要能实时的通知给第三方
一个风轻云淡
2023/10/15
1870
观察者模式解读
观察者模式(ObserverPattern)
场景 我们接到一个来自气象局的需求:气象局需要我们构建一套系统,这系统有两个公告牌,分别用于显示当前的实时天气和未来几天的天气预报。当气象局发布新的天气数据(WeatherData)后,两个公告牌上显示的天气数据必须实时更新。气象局同时要求我们保证程序拥有足够的可扩展性,因为后期随时可能要新增新的公告牌。 概况 这套系统中主要包括三个部分:气象站(获取天气数据的物理设备)、WeatherData(追踪来自气象站的数据,并更新公告牌)、公告牌(用于展示天气数据) WeatherData知道如何跟气象
张磊BARON
2018/04/13
6800
观察者模式(ObserverPattern)
观察者模式
还是老样子,无需求,不设计。更好的设计只是为了解决需求而诞生 有这样的一个需求:(天气预报的项目)
@派大星
2023/06/28
1580
观察者模式
23种设计模式之观察者模式
1.气象站可以将每天测量到的温度,湿度,气压等以公告的形式发布出去(比如发布到自己的网站或第三方)
暴躁的程序猿
2022/03/23
3030
23种设计模式之观察者模式
Head First设计模式——观察者模式
前言: 这篇文章我们以Head First设计模式中讲解的气象站为例,通过它的案列进行学分析和编码(C#)测试,并归纳总结出观察者模式。
SpringSun
2020/08/11
7030
Head First设计模式——观察者模式
扒去Spring事件监听机制的外衣,竟然是观察者模式
Spring中提供了一套默认的事件监听机制,在容器初始化时便使用了这套机制。同时,Spring也提供了事件监听机制的接口扩展能力,开发者基于此可快速实现自定义的事件监听功能。
程序新视界
2022/11/23
6480
扒去Spring事件监听机制的外衣,竟然是观察者模式
设计模式之观察者模式(一)
前面两篇已经带大家走进了设计模式的世界,了解了策略模式,还有基本的OO基础和OO原则,不知道你是否能读懂以及了解呢。接下来,我们就要进入第二个模式的学习了,观察者模式,让我们来一窥究竟吧。
程序员小跃
2019/12/25
4370
《Head First 设计模式》学习笔记 | 观察者模式
以书中的气象监测应用为例:现在有一个气象中心可以监测温度、湿度、气压三种数据,我们需要通过 WeatherData 对象来获取这些数据,然后将这些数据显示在特定的装置上。
江不知
2020/04/14
5250
06-05-设计模式 观察者模式
//在WeatherData中,当增加一个第三方,都需要创建一个对应的第三方的公告板对象,并加入到dataChange,不利于维护,也不是动态加入
彼岸舞
2022/05/28
2010
06-05-设计模式 观察者模式
(Head First 设计模式)学习笔记(2) --观察者模式(气象站实例)
应用概述: 某气象站通过传感器实时测量气温/湿度/压力等数据,要求设计一个系统,能让多种类型的公告栏自动更新这些数据(本例中有二类公告板:实时显示气温/温度公告板,动态统计最高/最低气温公告板) 解释: 应用观察者模式,把气温数据做为一个主题(也称为可观察者),让其它公告板当做观察者,通过订阅主题(也称通过观察"可观察者")来得知最新的信息(当然,观察者们也可以方便的退订,从而停止自动更新) 又一设计原则: 为了交互对象之间的松耦合设计而努力。 观察者接口 Code using System;
菩提树下的杨过
2018/01/23
5730
观察者模式——心有灵犀
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
100000860378
2018/09/13
3540
设计之禅——观察者模式
观察者模式也是非常好理解的模式之一,因为在生活中很容易找到类比,比如报纸、书刊订阅,手机app消息通知等等,所以仅通过名字大致也就能明白这个模式的作用。不过,从代码的层次来讲却有非常多的细节需要注意。
夜勿语
2020/09/07
3650
设计模式|02 观察者模式
博主的博客地址: https://www.jeffcc.top/ 博主学习设计模式用的书是Head First的《设计模式》,强烈推荐配套使用!
微笑的小小刀
2019/09/19
3170
设计模式|02 观察者模式
设计模式之观察者模式(二)
上一篇的观察者模式学习的还好吗?首先简单来回顾下上篇内容,有一个气象站的需求,需要在温度、湿度、气压改变的时候,实时更新三个布告板,以便能及时、准确的获取信息。所以,在设计模式的层面,我们最容易想到并且最正确的方式就是使用观察者模式来处理这个问题。
程序员小跃
2019/12/25
4790
java设计模式(六)--观察者模式
转载:设计模式(中文-文字版) 目录: 简单目标任务实现 观察者模式介绍 观察者模式代码实现 观察者模式是JDK中使用最多的模式之一,非常有用。我们也会一并介绍一对多关系,以及松耦合(对,没错,我们说耦合)。有了观察者,你将会消息灵通。 文章首先从一个案例入手开始介绍。这个案例是这样的,团队承包了一个气象站的气象发布系统。 工作合约 恭喜贵公司获选为敝公司建立下一代Internet气象观测站! 该气象站必须建立在我们专利申请中的W eatherD ata对象 上,由W eatherD ata对象负责追踪目前
Ryan-Miao
2018/03/13
1.1K0
java设计模式(六)--观察者模式
23种设计模式之观察者模式
最近在看Head First 设计模式,了解下观察者模式。书本上实现比较麻烦点,写个简单的。
用户2146693
2019/08/08
3890
23种设计模式之观察者模式
观察者模式
指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,它是对象行为型模式。主题(Subject)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的。
晚上没宵夜
2022/05/09
2330
相关推荐
Java设计模式之观察者模式
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验