java 观察者模式_重学 Java 设计模式:实战观察者模式「模拟类似小客车指标摇号过程,监听消息通知用户中签场景」...

一、前言

知道的越多不知道的就越多

编程开发这条路上的知识是无穷无尽的,就像以前你敢说精通Java,到后来学到越来越多只想写了解Java,过了几年现在可能想说懂一点点Java。当视野和格局的扩大,会让我们越来越发现原来的看法是多么浅显,这就像站在地球看地球和站在宇宙看地球一样。但正因为胸怀和眼界的提升让我们有了更多的认识,也逐渐学会了更多的技能。虽然不知道的越来越多,但也因此给自己填充了更多的技术栈,让自己越来越强大。

拒绝学习的惰性很可怕

现在与以前不一样,资料多、途径广,在这中间夹杂的广告也非常多。这就让很多初学者很难找到自己要的知识,最后看到有人推荐相关学习资料立刻屏蔽、删除,但同时技术优秀的资料也不能让需要的人看见了。久而久之把更多的时间精力都放在游戏、娱乐、影音上,适当的放松是可以的,但往往沉迷以后就很难出来,因此需要做好一些可以让自己成长的计划,稍有克制。

平衡好软件设计和实现成本的度°

有时候一个软件的架构设计需要符合当前条件下的各项因素,往往不能因为心中想当然的有某个蓝图,就去开始执行。也许虽然你的设计是非常优秀的,但是放在当前环境下很难满足业务的时间要求,当一个业务的基本诉求不能满足后,就很难拉动市场。没有产品的DAU支撑,最后整个研发的项目也会因此停滞。但研发又不能一团乱麻的写代码,因此需要找好一个适合的度,比如可以搭建良好的地基,实现上可扩展。但在具体的功能上可以先简化实现,随着活下来了再继续完善迭代。

二、开发环境

JDK 1.8

Idea + Maven

31f64566644137fdc1b7e180f80e18db.png

三、观察者模式介绍

简单来讲观察者 模式,就是当一个行为发生时传递信息给另外一个用户接收做出相应的处理,两者之间没有直接的耦合关联。例如;狙击手、李云龙。

除了生活中的场景外,在我们编程开发中也会常用到一些观察者的模式或者组件,例如我们经常使用的MQ服务,虽然MQ服务是有一个通知中心并不是每一个类服务进行通知,但整体上也可以算作是观察者模式的思路设计。再比如可能有做过的一些类似事件监听总线,让主线服务与其他辅线业务服务分离,为了使系统降低耦合和增强扩展性,也会使用观察者模式进行处理。

四、案例场景模拟

http://weixin.qq.com/r/W0Rqco7EptPZrcoR9xFJ (二维码自动识别)

在本案例中我们模拟每次小客车指标摇号事件通知场景(真实的不会由官网给你发消息)

可能大部分人看到这个案例一定会想到自己每次摇号都不中的场景,收到一个遗憾的短信通知。当然目前的摇号系统并不会给你发短信,而是由百度或者一些其他插件发的短信。那么假如这个类似的摇号功能如果由你来开发,并且需要对外部的用户做一些事件通知以及需要在主流程外再添加一些额外的辅助流程时该如何处理呢?

基本很多人对于这样的通知事件类的实现往往比较粗犷,直接在类里面就添加了。1是考虑 这可能不会怎么扩展,2是压根就没考虑 过。但如果你有仔细思考过你的核心类功能会发现,这里面有一些核心主链路,还有一部分是辅助功能。比如完成了某个行为后需要触发MQ给外部,以及做一些消息PUSH给用户等,这些都不算做是核心流程链路,是可以通过事件通知的方式进行处理。

那么接下来我们就使用这样的设计模式来优化重构此场景下的代码。

1. 场景模拟工程

itstack

这里提供的是一个模拟小客车摇号的服务接口。

2. 场景简述

2.1 摇号服务接口

public 

非常简单的一个模拟摇号接口,与真实公平的摇号是有差别的。

五、用一坨坨代码实现

这里我们先使用最粗暴的方式来实现功能

按照需求需要在原有的摇号接口中添加MQ消息发送以及短消息通知功能,如果是最直接的方式那么可以直接在方法中补充功能即可。

1. 工程结构

itstack

这段代码接口中包括了三部分内容;返回对象(LotteryResult)、定义接口(LotteryService)、具体实现(LotteryServiceImpl)。

2. 代码实现

public 

从以上的方法实现中可以看到,整体过程包括三部分;摇号、发短信、发MQ消息,而这部分都是顺序调用的。

除了摇号接口调用外,后面的两部分都是非核心主链路功能,而且会随着后续的业务需求发展而不断的调整和扩充,在这样的开发方式下就非常不利于维护。

3. 测试验证

3.1 编写测试类

@Test

测试过程中提供对摇号服务接口的调用。

3.2 测试结果

22:

从测试结果上是符合预期的,也是平常开发代码的方式,还是非常简单的。

六、观察者模式重构代码

接下来使用观察者模式来进行代码优化,也算是一次很小的重构。

1. 工程结构

itstack

观察者模式模型结构

221257cc661692597b2489835aac1470.png

从上图可以分为三大块看;事件监听、事件处理、具体的业务流程,另外在业务流程中 LotteryService 定义的是抽象类,因为这样可以通过抽象类将事件功能屏蔽,外部业务流程开发者不需要知道具体的通知操作。

右下角圆圈图表示的是核心流程与非核心流程的结构,一般在开发中会把主线流程开发完成后,再使用通知的方式处理辅助流程。他们可以是异步的,在MQ以及定时任务的处理下,保证最终一致性。

2. 代码实现

2.1 事件监听接口定义

public 

接口中定义了基本的事件类,这里如果方法的入参信息类型是变化的可以使用泛型<T>

2.2 两个监听事件的实现

短消息事件

public 

MQ发送事件

public 

以上是两个事件的具体实现,相对来说都比较简单。如果是实际的业务开发那么会需要调用外部接口以及控制异常的处理。

同时我们上面提到事件接口添加泛型,如果有需要那么在事件的实现中就可以按照不同的类型进行包装事件内容。

2.3 事件处理类

public 

整个处理的实现上提供了三个主要方法;订阅(subscribe)、取消订阅(unsubscribe)、通知(notify)。这三个方法分别用于对监听时间的添加和使用。

另外因为事件有不同的类型,这里使用了枚举的方式进行处理,也方便让外部在规定下使用事件,而不至于乱传信息(EventType.MQ、EventType.Message)。

2.4 业务抽象类接口

public 

这种使用抽象类的方式定义实现方法,可以在方法中扩展需要的额外调用。并提供抽象类abstract LotteryResult doDraw(String uId),让类的继承者实现。

同时方法的定义使用的是protected,也就是保证将来外部的调用方不会调用到此方法,只有调用到draw(String uId),才能让我们完成事件通知。

此种方式的实现就是在抽象类中写好一个基本的方法,在方法中完成新增逻辑的同时,再增加抽象类的使用。而这个抽象类的定义会有继承者实现。

另外在构造函数中提供了对事件的定义;eventManager.subscribe(EventManager.EventType.MQ, new MQEventListener())。

在使用的时候也是使用枚举的方式进行通知使用,传了什么类型EventManager.EventType.MQ,就会执行什么事件通知,按需添加。

2.5 业务接口实现类

public 

现在再看业务流程的实现中可以看到已经非常简单了,没有额外的辅助流程,只有核心流程的处理。

3. 测试验证

3.1 编写测试类

@Test

从调用上来看几乎没有区别,但是这样的实现方式就可以非常方便的维护代码以及扩展新的需求。

3.2 测试结果

23:

从测试结果上看满足 我们的预期,虽然结果是一样的,但只有我们知道了设计模式的魅力所在。

七、总结

从我们最基本的过程式开发以及后来使用观察者模式面向对象开发,可以看到设计模式改造后,拆分出了核心流程与辅助流程的代码。一般代码中的核心流程不会经常变化。但辅助流程会随着业务的各种变化而变化,包括;营销、裂变、促活等等,因此使用设计模式架设代码就显得非常有必要。

此种设计模式从结构上是满足开闭原则的,当你需要新增其他的监听事件或者修改监听逻辑,是不需要改动事件处理类的。但是可能你不能控制调用顺序以及需要做一些事件结果的返回继续操作,所以使用的过程时需要考虑场景的合理性。

任何一种设计模式有时候都不是单独使用的,需要结合其他模式共同建设。另外设计模式的使用是为了让代码更加易于扩展和维护,不能因为添加设计模式而把结构处理更加复杂以及难以维护。这样的合理使用的经验需要大量的实际操作练习而来。

作者:小傅哥

链接:人类身份验证 - SegmentFault

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

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

相关文章

图纸管理软件_造价20万以内的农村别墅长啥样?挑选5套图纸,让城里人羡慕吧...

在老家盖房算是一件“光宗耀祖”的事情&#xff0c;现在的物价高&#xff0c;想盖一栋房随便都要几十万&#xff0c;对于一般家庭来说&#xff0c;要拿出这笔数字并不是一件容易的事&#xff0c;通常大家的预算都有限&#xff0c;希望能花最少的钱盖最好的房&#xff0c;这种心…

python+ BeautifulSoup抓取“全国行政区划信息查询平台”的省市区信息

全国行政区划信息查询平台地址&#xff1a;http://xzqh.mca.gov.cn/map 检查网页源码&#xff1a; 检查网页源码可以发现&#xff1a; 所有省级信息全部在javaScript下的json中&#xff0c;会在页面加载时加载json数据&#xff0c;填充到页面的option中。 1.第一步&#xff1…

32利用文件系统保存数据_网易技术实践|Docker文件系统实战

在本文中&#xff0c;我们来实战构建一个Docker镜像&#xff0c;然后实例化容器&#xff0c;在Docker的生命周期中详细分析一下Docker的文件存储情况和DockerFile优化策略。在开始实战之前&#xff0c;我们先介绍一个概念&#xff0c;联合文件系统&#xff08;Union File Syste…

二叉树遍历的超简单方法(详细、简单)

二叉树遍历的超简单方法 参考链接&#xff1a;https://wenku.baidu.com/view/e5463e4203d8ce2f0166230a.html 已修改部分问题。 三种常见二叉树的遍历&#xff1a; 先序遍历的递归算法定义&#xff08;简称根左右&#xff09; 若二叉树非空&#xff0c;则依次执行如下操作&a…

怎么看我装的sql能不能用_深入浅出sql优化(三)之单表索引优化

大家好&#xff0c;我是闲水&#xff0c;每天更新java最新最热技术&#xff0c;对java感兴趣的朋友记得关注一下哦。注意 &#xff1a;这是SQL性能优化第三章&#xff0c;点击关注查看前置内容。上篇文章我们主要了解了索引优化的标尺"Explain"怎么用&#xff0c;这一…

java类加载顺序(spring容器下)

执行顺序&#xff1a;父类静态块–>子类静态块–>父类非静态块–>父类构造方法–>子类非静态块–>子类构造方法–>自动装载的方法 子类和父类均加上Service注解&#xff0c;将其交给spring容器管理。 父类&#xff1a; Service public class Father {publ…

jwt token 太长_理解 JWT 鉴权的应用场景及使用建议

JWT 介绍JSON Web Token(JWT)是一个开放式标准(RFC 7519)&#xff0c;它定义了一种紧凑(Compact)且自包含(Self-contained)的方式&#xff0c;用于在各方之间以JSON对象安全传输信息。这些信息可以通过数字签名进行验证和信任。可以使用秘密(使用HMAC算法)或使用RSA的公钥/私钥…

microsoft vbscript编译器错误怎么解决_win7系统ie应用程序错误怎么办 ie应用程序错误解决方法【详解】...

windows系统自带的ie浏览器很少用户会去使用到&#xff0c;它运行起来比其他的浏览器要慢很多&#xff0c;而且经常会出现各种各样的问题&#xff0c;最近有位win7系统用户&#xff0c;在使用ie浏览器的时候&#xff0c;发生了应用程序错误的情况&#xff0c;那么win7系统ie应用…

修改固态硬盘的物理序列号_买固态怕踩坑?收下这些软件,轻松鉴别好坏

再有半个月&#xff0c;就迎接年中的促销旺季。不少朋友都希望趁着各种优惠、跳楼价&#xff0c;组一台梦想机、升级一下自己的电脑。说到体验升级&#xff0c;相信就算是DIY新手和硬件小白都知道&#xff0c;要想电脑快&#xff0c;必须选固态。但是固态参数多&#xff0c;又是…

《常用控制电路》学习笔记——数控锁相环调速电路

序言 今天开始我将把自己学习《常用控制电路》的一些内容发到互联网上&#xff0c;希望能和大家交流学习。 这本书主要介绍了一系列控制电路的经典案例&#xff0c;进行了电路和代码的设计&#xff0c;我将把这本书中学习到的内容和学习的过程尽量准确的分享出来与大家交流&…

《常用控制电路》学习笔记——数字控制直流电动机调速电路

书中该节讲述的电路通过ADC芯片将电位器的阻值转换为电压量&#xff0c;然后使用单片机输出PWM进行电路控制。本电路也可扩展应用至需要模拟量输入与输出的场合。 目录 一、系统设计思路 二、各模块电路分析 2.1电路构成 2.2工作状态分析 三、程序分析 3.1 变量定义 3.…

《常用控制电路》学习笔记——数控直流恒流源电路

书中该项目内容设计了一个从交流220V市电作为供电电源的恒流源电路&#xff0c;并且此电路可由加减计数器74LS193控制输出的电流大小。 目录 一、系统方案 二、各模块电路分析 整流滤波及稳压电路 数字量控制电路 数模转换电路 数控恒流源产生电路 三、电路仿真结果 四…

图像太宽无法输出请裁剪图像或降低分辨率然后重试_真·无监督!延世大学提出图像到图像无监督模型,实验结果超SOTA...

作者 | 蒋宝尚编辑 | 丛 末图像翻译目的是用模型将源域图像转换到目标域图像&#xff0c;通常涉及标签图到场景图的转换、图像风格、人脸的属性变换、标签图到场景图的转换。图像翻译任务自生成对抗网络提出就得到了快速发展&#xff0c;例如经典的pix2pix、CycleGAN、StarGAN。…

php serialize和json_encode哪个更快_世界 10 大编程语言,Java 不是第一,PHP 才第五...

来源&#xff1a;toutiao.com/a6764554659349676557/如果你是软件开发领域的新手&#xff0c;那么你会想到的第一个问题是“如何开始&#xff1f;”编程语言有数百种可供选择&#xff0c;但是你怎么发现哪个最适合你&#xff0c;你的兴趣和职业目标又在哪里呢&#xff1f;选择最…

tomcat7.0支持什么版本的jdk_恭喜你喜提JDK,那你知道JDK是什么吗?先来看看吧

点击蓝字关注一行JDK 大家都知道电脑的操作系统是由汇编和C语言写出&#xff0c;因此操作系统无法直接识别其他语言。这时我们就需要为我们写的Java程序配备一名翻译官 ----- 编译环境&#xff0c;将Java程序翻译成电脑可以识别的程序&#xff0c;C或者汇编。 那么对于这个…

我的python 入门 安装 -- hello world

我的python 安装–>“hello world” 最近老听到关于python的声音&#xff0c;而且越来越强烈。就好奇下载了下&#xff0c;在win10 的应用商店下载的 够傻瓜了吧 环境变量也不用配置 直接上手 hello world了 cmd 窗口 输入 python -v 正常显示 显示版本号 不能正常显示…

记录spring、springboot集成apollo配置中心

一, spring集成apollo&#xff0c;前提是apollo配置中心服务端已经在运行中 上面是我在阿里云服务搭建的apollo配置中心服务端&#xff0c;登录后的样子。没有搭建服务端的小伙伴&#xff0c;请先搭建好apollo的服务端 然后点击‘创建项目’&#xff0c;新建测试用的项目 填…

基本农田卫星地图查询_发现谷歌地图替代网站,卫星地图街景功能都能用

众所周知&#xff0c;由于谷歌地图&#xff08;Google Maps&#xff09;在国内不能访问&#xff0c;很多人就没有办法通过谷歌地图来获得服务。谷歌地图是目前全球最受欢迎的世界地图网站&#xff0c;在2005年以前&#xff0c;谷歌地图就收录了美国、英国、加拿大三个国家的地图…

记录 Linux crontab 的使用

记录一次简单的Linux定时任务----》每周定时备份数据库结构及数据 环境&#xff1a;阿里云服务器 vim 命令&#xff1a;输入i/a 进入输入模式&#xff0c;输入完成后&#xff0c;esc键&#xff0c;退出输入模式&#xff0c;确定无误后&#xff0c;输入“:wq”,保存退出 Linux 环…

python random函数_Python随机函数random使用详解

在python中用于生成随机数的模块是random,在使用前需要import, 下面看下它的用法。1、random.randomrandom.random()用于生成一个0到1的随机符点数: 0 < n < 1.0注意&#xff1a; 以下代码在Python3.5下测试通过&#xff0c; python2版本可稍加修改描述random() 方法返回…