经历这么多版本RxJava本质上不变的是什么?
RxJava的版本从发布到现在,已经经历了好多个版本了,虽然源码在不断的修改,但是不知你有没有发现,RxJava的主体架构还是没有变化,为什么呢?可以说是RxJava架构决定了它的特性,比如代码逻辑的简洁以及操作符带来极强的扩展能力,这些在RxJava迭代了这么多个版本之后,这些特性,没有减少,反而大大的增强了,这个特性,就是响应式编程,那么接下来,就来讲讲RxJava为什么会有这种特性,以及带来其特性不变的本质是啥!
本文主要讲解RxJava的架构思想,不会涉及到大量的源码分析,请放心食用,文章篇幅较长,建议收藏,慢慢品尝!
虽然RxJava的版本更新没有那么频繁,但是每次的更新,总会让人感觉,之前刚看的源码,是不是前功尽弃了,源码一更新,我又得继续去学习;
但是不知你是否有这样想过,框架一直在更新,底层有没有不变的东西,今天很高兴告诉你,RxJava框架有,那么这个不变的东西是什么呢?
没错,RxJava虽然迭代了几个版本,但是其底层的架构还是没有怎么变动,为什么呢?因为其特性就决定了它的架构不会有多大的变化;
就好比一栋房子,其特性有抗震,防风,那么其底层的架构就是必然是按着抗震和防风的特性去建造的,而一旦建造成功,其具有的特性,不会跟着房子的装修而变化,那么其底层的架构也是同样的道理;
RxJava的观察者模式,是扩展的观察者模式,为啥要叫扩展呢?因为它和普通的观察者模式不太一样,扩展的观察者模式,不止一个通知观察者的方法,它有好几个,下面我们来看看它的实现原理吧!
下面我们来看一RxJava的事件类型,这个事件是被观察者用来通知观察者的,也就是Event,而Event可以分为下面几种类型,这个我们了解一下即可;
Next:常规事件,可以传递各种各样的数据;Complete:结束事件,当观察者接收到结束事件后,就不会再接收后续被观察者发送来的事件;Error:异常事件,当被观察者发送异常事件后,那么其他的事件就不会再继续发送了;
Observer类的方法很简单,都是回调,这里有个新的接口类Emitter,这个Emitter是用来干嘛的呢?
实现逻辑就是通过包装Observer,里面最终是通过Observer来进行调用的,来看看这个类有哪些方法;
这个类的逻辑很简单,就两步,第一步,进行订阅,第二步,回调Emitter对象,用于发射事件;
当订阅成功之后,被观察者的subscribe方法里面,就可以通过发射器发射各种事件,最终在观察者的方法里进行回调;
RxJava也是观察者和被观察者订阅的过程,只是被观察者有变化的时候,是通过发射器来发射各种事件的,这样就不局限于一种事件了;
要理解这个模式其实不难,我们从“装饰”这两个字就可以看出,这个模式用于装饰用的,至于怎么装饰,且听我细细道来;
比如说我现在有一个手机,我怎么在不改变这个手机原有的结构,而让其具有防摔的功能,当然你也可以说我的手机是诺基亚,从几楼往下丢,手机都不带磕碰的,但是现实是,我们使用的手机,并不是那么的抗摔;
相信答案你已经很清楚了,就是套手机壳,贴膜,而这两个动作,是在没有改变手机原有的结构上,让其具有了抗摔的功能,而这个过程可以称为装饰,而装饰者模式的原理也是如此;
同理,假如我们要在一个类上添加新功能,而不修改其原有的逻辑,那么我们这时候就可以使用装饰者模式进行封装,具体怎么做,我们下面来看看;
还是以上面为例子,定义一个外观的接口Appearance,有一个抽象的方法,结构structure;
然后再定义一个手机类Phone实现这个接口,这个手机的结构有玻璃后盖,金属边框等属性,如下:
如果不能修改其原有的结构,那么我可以通过装饰来对手机进行包装,先定义一个手机的包装类,用来包装手机,命名为PhoneDecorator,实现了Appearance接口,在这里通过构造方法传进来的外观类Appearance,调用了外观类的structure方法,保证其原有的功能实现;
那么接下来就是包装类的具体实现了,定义一个套手机壳功能的类PhoneShell,功能实现就是在原有功能的基础上,给手机套上手机壳,来看看具体实现吧;
那么套手机壳的类有了,还差一个贴膜的类,和手机壳一样,我们也来定义一个贴膜的包装类PhoneCover,看看具体实现;
使用起来很简单,将需要包装的类,作为构造参数,传入到包装类里面,就可以让这个类具有包装的功能,比如这里,将手机Phone传入到手机壳PhoneShell的类里面,那么手机就有套上手机壳的功能了;
同理,再将套上手机壳的手机PhoneShell类,传入到贴膜的类PhoneCover里面,那么这个手机就具有了贴膜的功能,最后再调用一下结构的方法structure,那么就可以看到这个手机已经被套上手机壳,并且贴上膜了;
因为继承随着功能的增加,会导致子类越来越膨胀,而装饰者模式的双方可以随意扩展,不会相互耦合;
RxJava的装饰者主要是用于实现被观察者Observable和观察者Observer的包装,为什么要进行包装呢?
假如我想实现这样一种功能,在子线程获取数据,然后切换到主线程进行数据的赋值,正常情况下我们会这样做,先在子线程获取数据,然后再通过Handler的post方法,切到主线程;
如果按照常规的实现逻辑,这样的代码就会很混乱,作为一名有追求的工程师,我们是无法忍受这样的写法的;
RxJava通过装饰者模式+观察者模式设计出了链式调用的效果,这样代码逻辑清晰,也方便维护;
第一步:要有一个抽象接口对应上面的Appearance接口,而RxJava的接口是ObservableSource,里面有一个方法,subscribe,用于和观察者进行订阅;
第三步:接下来就是具体的包装类了,和上面一样具有包装功能的PhoneShell,PhoneCover等等,而RxJava的包装类,非常强大,先看个图;
第一步:要有一个抽象接口对应上面的Appearance接口,而RxJava的接口是Emitter和Observer,里面有好几个方法,基本一样,onNext,onError,onComplete,用于被观察者进行回调;
第二步:要有一个包装类,实现了Emitter或者Observer接口,观察者比较特殊,没有一个基础的包装类,而是直接封装了很多的包装类;
从上面的例子,可以知道,包装类是有一个过程的,有的是在创建的时候就进行包装了,而有的是在调用的时候进行包装的;
而RxJava的被观察者是在创建的时候进行包装的,比如上面的示例代码,第一步,通过Observable.create方法,里面通过创建ObservableCreate对象,进行了第一层的包装,此时的结构如下:
最终调用订阅的方法的时候,已经进行了四次包装,可以这么理解,每调动一次操作符,那么就会进行一层被观察者的包装;
这进行了这么几次包装的作用,就是为了添加额外的功能,那么来大概看一下每一层添加的额外功能有啥?
上面我们知道,被观察者的包装,是在subscribeActual方法里,进行实现的,那么我们来看看这几个包装类的subscribeActual方法的逻辑;
这里会将观察者进行一层包装,也就是ObserveOnObserver,这个ObserveOnObserver的包装,里面实现了线程切换的逻辑,具体逻辑在onNext里面;
为什么要这么做呢?因为这就是装饰者模式带来的好处,这个onNext的被观察者通知观察者会回调的方法,然后这里通过包装类,在里面实现了额外的线程切换的功能,这里会切换到主线程去执行;
这一层包装类的subscribeActual方法又对观察者做了一层包装,也就是SubscribeOnObserver类,这个包装类又实现了什么功能呢?
让我们回到被观察者的实现逻辑,下面就调用了执行线程的方法,scheduleDirect,如果你传进来的是子线成的线程调度器Scheduler,那么SubscribeTask就会在子线程执行,而我们这里传的就是子线程;
这里对观察者做了一层包装,也是CreateEmitter类,来看这个观察者的包装类又实现了什么额外的功能呢?
然后我们在ObservableOnSubscribe的subscribe方法里调用了发射器,发射字符串,那么这时候的调用逻辑是怎样的呢?
从上面观察者的结构来看,当发射器发送事件时,会一层层的回调对应的观察者包装类,从最外面一层开始;
上面我们知道ObservableEmitter类是CreateEmitter对观察者的包装,那么这个onNext就会走CreateEmitter的onNext方法,上面我们知道这个方法只是做了判断,最终还是回调给上一层的包装类的onNext方法;
再上一层的包装类是SubscribeOnObserver,这个方法的onNext没有对观察者做任何处理;
那么还是得继续往上一层的包装类进行查看,上一层的包装类是ObserveOnObserver,这个类的onNext方法,执行了线程的切换,最终切换到主线程执行;
我们在创建被被观察者的时候,会对被观察者做一层包装, 创建几次就包装几次,然后再被观察者调用subscribe方法时,一层层回调被观察者的subscribeActual方法,而在被观察者的subscribeActual方法里,会对观察者做一层包装;
也就是说被观察者是在创建的时候进行包装,然后在subscribeActual方法里实现额外的功能;
而观察者是在被观察者调用subscribeActual方法里进行包装的,然后针对观察者实现自己额外的功能;
第二步:被观察者订阅观察者,这时候会一层层的回调被观察者的包装类的subscribeActual方法,然后对观察者进行包装;
此时,被观察者的功能实现是在subscribeActual方法里,而观察者的实现是在包装类里;
第三步:被观察者和观察者不同的是,被观察者是在订阅成功之后,就执行了包装类相应的功能,而观察者是在事件回调的时候,会在观察者的包装类里实现对应的功能;
比如我进入一个列表页,这个列表页的数据,需要从好几个接口请求返回的,而请求返回后我还要根据数据和网络来展示对应的页面,比如列表页或者无数据,无网络的页面,那么我展示的逻辑就是根据列表页返回的逻辑来展示的;
事务A,事务B,事务C分别对应请求网络接口的数据,而事务D则是根据返回的数据处理展示的逻辑;
那么我正常的处理逻辑可能是这样,在子线程去处理这三个事务A,事务B,事务C,最终等都处理完了之后,再处理事务D,而这样写的坏处就是我把这几个接口的数据都放在一个子线程去执行了,那么最终结果就是会导致加载缓慢;
那么我们是否可以换成另外一种写法,事务A,事务B,事务C分别在三个子线程去执行,然后最终在三个子线程的回调里面去判断这几个接口是否已经加载完毕了,这样可以解决上面的问题,但是如果以后还有新增的事务,那么最终会导致判断的逻辑越来越臃肿;
我们可以理解为由事件来驱动事务,比如我请求网络数据成功了,发送请求成功的事件通知下一层事务进行处理;
而RxJava提供了一系列的特性,比如我们可以对事务进行变换,串联,组装等来对事务进行操作,比如上面的事务A,事务B,事务C,我们可以通过组装的方式来进行处理;
1、大幅度降低事务之间的耦合性,方便后期维护与扩展;2、简化复杂的线程操作,让我们专注于业务开发,避免了很多线程并发的问题,比如线、提供了丰富的操作符,让我们对于事务的处理更加方便;4、对于复杂的业务,我们可以构建出清晰的代码逻辑,方便理解业务逻辑;
- 标签:本站
- 编辑:杨保录
- 相关文章
-
经历这么多版本RxJava本质上不变的是什么?
对房屋进行装修的时候,我们都会优先选择口碑比较好的装修公司,那么郑州最好的装修公司有哪些呢?今天小编为大家盘点了郑州装修…
-
2021年郑州装修公司排名前十强 2021郑州十大装修公司排名榜
对房屋进行装修的时候,我们都会优先选择口碑比较好的装修公司,那么郑州最好的装修公司有哪些呢?今天小编为大家盘点了郑州装修…
- 2019威海住宅产业博览会·九艺三星装饰丨参与住博会 展示家装名企风采
- 郑州市吊顶铝方通装修公司(新推荐!2022已更新)
- 面向对象、设计原则、设计模式、编程规范、重构这五者有何关系
- 三星装饰荣获质量、服务、诚信五星级企业
- 长沙金煌健康住宅新整装加速推动进入美好生活新方式