看了这么多年西游记,你可知道孙悟空是如何召唤土地公公的吗?

小时候最开心的事莫过于躺在沙发上看《西游记》了。大闹天宫、三打白骨精、真假美猴王……一幕幕精彩的故事萦绕脑海,现在想来,回味无穷。

不知道你有没有注意到这个细节:每当孙悟空到了一个新的环境需要了解本地的”风土人情”时,都会挥舞一下金箍棒,将土地召唤出来。那么你可知道,土地公公接收孙悟空召唤的原理是什么吗?

我们可以先将其理解为” 事件通知机制“,即每当孙悟空将金箍棒敲在地上时,就相当于给土地发了一封 email 的通知,告诉他俺老孙来了,赶快出来接驾。当土地收到通知之后就会立即现身了。

大家都知道 Spring 已经为我们提供好了 事件监听、订阅的实现,接下来我们用代码来实现一下这个场景。

首先我们要定义一个事件,来记录下孙悟空敲地的动作。

@Getter
public class MonkeyKingEvent extends ApplicationEvent {

    private MonkeyKing monkeyKing;

    public MonkeyKingEvent(MonkeyKing monkeyKing) {
        super("monkeyKing");
        this.monkeyKing = monkeyKing;
    }

}

其中 MonkeyKing 是我们定义好的孙悟空的实体类

@Data
public class MonkeyKing {

    /**
     * 是否敲地,默认为否
     **/
    private boolean knockGround = false;

}

然后我们需要实现 ApplicationListener 来监听孙悟空敲地的动作。

@Component
public class MyGuardianListener implements ApplicationListener {

    @Override
    public void onApplicationEvent(MonkeyKingEvent event) {
        boolean knockGround = event.getMonkeyKing().isKnockGround();
        if(knockGround){
            MyGuardian.appear();
        }else{
            MyGuardian.seclusion();
        }
    }
}

最后我们来验证下整个流程。

@PostMapping
public void testEvent(@RequestParam boolean knockGround) {
    MonkeyKing monkeyKing = new MonkeyKing();
    monkeyKing.setKnockGround(knockGround);
    MonkeyKingEvent monkeyKingEvent = new MonkeyKingEvent(monkeyKing);
    //发布孙悟空敲地的动作事件
    applicationEventPublisher.publishEvent(monkeyKingEvent);
}

当我们调用 testEvent()方法传入 knockGroundtrue 时,打印

土地公公出现了

传入为 false时,打印

土地公公遁地了

这样我们就简单实现了”孙悟空召唤土地”的功能。你以为这样就结束了?从小老师就教导我们要”知其然,更要知其所以然”。

大家都说读源码更像是在喝咖啡,读不懂又苦又涩,读懂了浓郁醇香。为了不影响大家的好心情,这里我们就不研究它的源码了,我们直捣黄龙。

说是 事件通知机制也好, 事件监听-订阅的实现也罢,其实它内部的最终实现原理依赖的是观察者模式。看到这,先不要胆怯,不要觉得设计模式晦涩难懂、久攻不下。今天我就用通俗易懂的小故事来带你重新认识一下观察者模式。

故事是这样的,上边我们只说了孙悟空敲地的动作,但是你是否还记得孙悟空将金箍棒往天上一指,便换来雷公电母、龙王等为其施法布雨?闭上双眼,与虎力大仙比试的场景仍历历在目。

由此可见,不光土地能收到孙悟空的通知,连雷公电母和龙王也是可以接收到的。在这里,我们把孙悟空比作主题,也就是大家说的被观察者和 Subject的概念,把雷公电母和龙王以及土地比作观察者。

以下是我们的代码逻辑:

首先,我们定义一个主题的基础类,里边会记录所有订阅该主题的观察者列表,还包含了增加、删除以及通知观察者的方法。

public class Subject {

    //观察者列表
    private Vector vector = new Vector();

    /**
     * 增加观察者
     **/
    public void addObserver(Observer observer){
        vector.add(observer);
    }

    /**
     *  删除观察者
     **/
    public void deleteObserver(Observer observer){
        vector.remove(observer);
    }

    /**
     *  通知所有观察者
     **/
    public void notifyObserver(String goldenCudgel) {
        for(Observer observer : vector) {
             observer.update(goldenCudgel);
         }
    }

}

然后,我们定义一个观察者的接口,包含观察者收到通知之后的”动作”。

public interface Observer {
    void update(String goldenCudgel);
}

这时候我们再分别定义出”土地”、”雷公电母”、”龙王”的观察者实体类,实现具体的打雷下雨等动作。

“雷公电母”、”龙王”等实现与”土地”类似,故此处仅展示观察者”土地”。

@Component
public class MyGuardianObserver implements Observer {

    @Override
    public void update(String goldenCudgel) {
        if(upGoldenCudgel(goldenCudgel)) {
            System.out.println("土地公公出现了");
        }
    }

    public boolean upGoldenCudgel(String goldenCudgel){
        if(Objects.equals(goldenCudgel,"down")){
            return true;
        }
        return false;
    }

}

接着,我们就可以定义被观察者的具体实现类”孙悟空”了

public class MonkeyKingSubject extends Subject{

    /**
     * 金箍棒是举起来还是放下呢?哈哈,你猜猜。。。
     **/
    public void doGoldenCudgel(String goldenCudgel){
        notifyObserver(goldenCudgel);
    }

}

最后我们来做个测试看看他们能不能响应孙悟空的通知。

@PostMapping
public void observerTest(){
    MonkeyKingSubject subject = new MonkeyKingSubject();
    subject.addObserver(new ThunderGodObserver());
    subject.addObserver(new MyGuardianObserver());
    subject.addObserver(new DragonKingObserver());

    subject.doGoldenCudgel("up");
    System.out.println("我是分割线-----------------------------");
    subject.doGoldenCudgel("down");
}

结果展示

雷公电母发出电闪雷鸣
龙王前来下雨
我是分割线-----------------------------
土地公公出现了

故事的最后怎么能少的了总结呢?观察者模式与事件通知机制都是在一对多的关系中,当一个对象被修改时,则会自动通知依赖它的对象,两者之间相互独立,互相解耦,这样既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。

当然它的缺点也不容忽视:

文章的最后,照例奉上源码,后台回复 event 即可获取。以上就是今天的全部内容了,如果你有不同的意见或者更好的 idea,欢迎联系阿Q,添加阿Q可以加入技术交流群参与讨论呦!

Original: https://www.cnblogs.com/aqsaycode/p/15627881.html
Author: 阿Q说代码
Title: 看了这么多年西游记,你可知道孙悟空是如何召唤土地公公的吗?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/685580/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 约瑟夫循环

    简单粗暴 什么是约瑟夫循环 举个例子 1 2 3 4 四个人 从头开始报数 报到3 的人 淘汰 然后继续报数 规则依旧 我们来演示一下 开始是1 2 3 4 3 数3 淘汰 (下面…

    技术杂谈 2023年7月23日
    080
  • Microsoft Teams平台手册公开邀请试读

    这本书的全名为《Microsoft Teams平台完全手册》,可以简称为 《Teams平台手册》,我准备从几个不同的维度,给读者展现完整的Microsoft Teams平台,包括但…

    技术杂谈 2023年5月31日
    0105
  • ntpd dead but pid file exists

    ntpd -gnqd ntpd 4.2.2p1@1.1570-o Fri Jul 22 18:07:53 UTC 2011 (1) addto_syslog: precision …

    技术杂谈 2023年5月30日
    089
  • BD

    Loading 销售圣经:终极销售资源(销售必读,行业经典) 销售圣经2:销售之神的21.5条销售法则 Heart and Sell: 10 Universal Truths Ev…

    技术杂谈 2023年5月30日
    0106
  • Android:hook很“危险”,使用需谨慎。

    前言 上篇文章《Android安卓进阶技术分享之AGP工作原理》和大家分析了 AGP(Android Gradle Plugin) 做了哪些事,了解到 AGP 就是为打包这个过程服…

    技术杂谈 2023年7月10日
    0104
  • TestLink在线Excel用例转换xml

    项目功能 TestLink在线Excel用例转换xml将符合用例模板的Excel测试用例,转换成xml,用于导入TestLink进行用例管理。 使用方法 1、编写测试用例 2、打开…

    技术杂谈 2023年7月11日
    060
  • 如何构建你自己的计算机网络知识体系?

    大家好,我是小牛肉,不知道各位曾经有没有和我一样的困惑,就是有些知识好像已经看了好多遍了,但是知识点在脑子中是分散的,没办法串联起来,别人问一个问题我能答出来一点,但是你让我自己从…

    技术杂谈 2023年7月25日
    081
  • idea Transparent-native-to-ascii 是否需要勾选?

    首先看一下官方对该选项的解释: 第一段是说标准的Java api是用 ISO 8859-1编码 .properties文件的,所以如果你在properties文件中可以使用转义序列…

    技术杂谈 2023年7月11日
    071
  • 面向对象编程-基础

    面向对象是一种”建模思想” 把现实中的各种事物”虚拟化到程序中”(定义类就是一种封装) 类:对现实生活中一类具有共同属性和行为的事物…

    技术杂谈 2023年6月21日
    085
  • 你真的懂Python命名吗?

    转载请注明出处❤️ 作者:测试蔡坨坨 原文链接:caituotuo.top/7417a7f0.html 大家好,我是测试蔡坨坨。 今天,我们来聊一下Python命名那些事儿。 名为…

    技术杂谈 2023年7月11日
    079
  • spring-boot-导出excel-xlsx 文件损坏

    maven的pom文件处理 ①将resource标签配置如下 src/main/resources true bootstrap.yml **/*.xml **/excelTemp…

    技术杂谈 2023年7月25日
    081
  • 技术人的慰藉

    当我屡次不经意地凝视自己的博客时,边栏上的园龄一项总会不揣冒昧地提醒我 —— 某人已躬耕十年。当年万里觅封侯,匹马戍梁州。如今听雨客舟中,江阔云低,断雁叫西风 —— 十年,注定是一…

    技术杂谈 2023年6月1日
    0111
  • 技术管理进阶——管理者可以使用哪些管理工具

    原创不易,求分享、求一键三连 前段时间有个粉丝问了一个问题: 小钗,成为Leader后,我到底有什么管理工具可以使用呢? 很好的问题,其实前文已经介绍了组织执行力的三要素:意愿、能…

    技术杂谈 2023年6月1日
    078
  • Linux C/C++ 获取进程号、线程号和设置线程名

    在Linux开发过程中,设计多线程开发时可以将进程和线程的 id 打印出来,方便开发调试和后期查问题使用,同时也包括设置线程名。 2.1 进程ID #include <uni…

    技术杂谈 2023年7月24日
    071
  • 语音开源库积累

    音频采集播放 OpenAL OpenAL 最初是由 Loki Software 所开发。是为了将 Windows 商业游戏移植到 Linux 上。Loki 倒闭以后,这个专案由自由…

    技术杂谈 2023年5月31日
    0110
  • 动态规划之矩阵连乘

    什么是动态规划 动态规划(英语:Dynamic programming,简称 DP),是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子…

    技术杂谈 2023年7月11日
    0112
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球