重新理解响应式编程

2022-12-06 0 626

译者:凯尔特吴 书名:https://www.jianshu.com/p/c95e29854cb1

序言

这是前几日我在公司内部Android组的技术撷取会后,以积极响应式程式设计为主轴做的两个专题撷取,意见反馈还极好,但也有许多难题,因而我根据意见反馈再次修正和健全了相关的阐释,组成一则该文撷取给大家。

研究那个难题的本意在于现阶段许多人对RxJava此种库,和它另一面所充分体现的程式设计价值观了解太少,而网上也极少有人能够把它讲明白,许多时候根本无法参照互联网路上的一些RxJava项目课堂教学去学习RxJava的采用。但我坚信,只有熟识积极响应式程式设计的价值观,就可以更快的采用RxJava那个Rx开拓库。

现阶段互联网路上中英文的数据资料对积极响应式程式设计的叙述有些两极化,或者根本无法将积极响应式的概念说明清楚,没有可理论性,或者从RxJava的表述起程来说明积极响应式程式设计。比如说“积极响应式程式设计是触发器报文程式设计”此种话,貌似紧紧抓住了重点,但是实际上你极难从那个表述中斩获管用的东西。

因而,今天我希望谈谈积极响应式程式设计的价值观和它的优势,和什么样去认知积极响应式程式设计就可以更快的把它带入到他们的程式设计工作中,把积极响应式程式设计变成他们手里的法宝。

积极响应式的来历

他们嘿嘿聊聊聊积极响应式的来历,对它的来历,他们可能须要先从几段常用的标识符短片看起

int a=1; int b=a+1; System.out.print(“b=”+b)    //  b=2 a=10; System.out.print(“b=”+b)    //  b=2

下面是几段很常用的标识符,简单的抒发式列印句子,但此种标识符有两个瑕疵,那是如果他们想抒发的并不是两个抒发式姿势,而是b和a之间的亲密关系,即无论a如何变化,b总有一天比a大1。那么他们就须要花附加的心力去构筑和保护两个b和a的亲密关系。

而积极响应式程式设计的设想正是试图用这种运算符帮助你构筑此种亲密关系。

它的价值观完全可以用下面的标识符短片来抒发:

int a=1; int b <= a+1;   // <= 符号只是表示a和b之间亲密关系的运算符 System.out.print(“b=”+b)    //  b=2 a=10; System.out.print(“b=”+b)    //  b=11

这是积极响应式的价值观,它希望有这种方式能够构筑亲密关系

,而不是执行这种抒发式命令。

至此你可能不禁要问,他们为什么须要构筑亲密关系的标识符而不是命令式的标识符呢?如果你翻一翻自己正在开发的APP,你就能看到的每两个交互的页面其实内部都包含了一系列的业务逻辑。而产品的每个需求,其实也对应了一系列的业务逻辑相互作用。总之,他们的开发是在构筑一系列的业务逻辑之间的亲密关系。你说他们是不是须要构筑亲密关系的标识符?

说回积极响应式,前期由于真实的程式设计环境中并没有构建亲密关系的运算符,主流的程式设计语言并不支持此种构筑亲密关系的方式,所以一开始积极响应式主要停留在想的层面,直到出现了Rx和一些其他支持此种价值观的框架,才真正把积极响应式程式设计引入到了实际的标识符开发中。

Rx是积极响应式开拓,即支持积极响应式程式设计的一种开拓,为积极响应式在不同语言中的实现提供指导价值观。

什么是积极响应式程式设计

说完了积极响应式的来历,他们就可以谈谈什么是积极响应式程式设计了。

积极响应式程式设计是一种通过触发器和报文来构筑事物亲密关系的程式设计模型

。这里每个词都很重要,“事物的亲密关系”是积极响应式程式设计的核心理念,“报文”和“触发器”是实现那个核心理念的关键。为了帮助大家认知那个概念,他们不妨以APP初始化业务为例来拆解一下这几个词。

重新理解响应式编程

这是两个比较理想化的APP初始化逻辑,完成SDK初始化,数据库初始化,登陆,之后跳转主界面。

事物的亲密关系

事物

是两个十分宽泛的概念,它可以是两个变量,两个对象,几段标识符,几段业务逻辑…..但实际上他们往往把事物认知成几段业务逻辑(下文你均可以将事物替换为业务逻辑来认知),比如说上图中,事物是指APP初始化中的四个业务逻辑。

事物的亲密关系

此种亲密关系不是类的依赖亲密关系,而是业务之间实际的亲密关系。比如说APP初始化中,SDK初始化,数据库初始化,登陆接口,他们共同被跳转页面业务所依赖。但他们三个本身并没有关联。这也只是业务之间较为简单的亲密关系,实际上,根据他们的需求App端会产生出许多业务之间错综复杂的亲密关系。

报文

关于Rx的报文有很多说法,比如说“Everything is a stream”,“Thinking with stream”等等。虽然我明白这只是想强调流的重要性,可是这些话折射出来的程式设计思路其实是很虚无缥缈的,只会让开发者对Rx程式设计更加迷惑。

实际上,报文只是事物之间沟通的桥梁。

比如说在APP初始化中,SDK初始化,数据库初始化,登陆接口这些业务完成之后才会去安排页面跳转的操作,那么这些上游的业务在自己工作完成之后,就须要通知下游,通知下游的方式有许多种,其中最棒的的方式是通过数据(事件)流。每两个业务完成后,都会有一条数据(两个事件)流向下游,下游的业务收到这条数据(那个事件),才会开始自己的工作。

但,只有报文是不能完全正确的构筑出事物之间的亲密关系的。他们依然须要触发器程式设计。

触发器

触发器程式设计本身是有许多优点的,比如说挖掘多核心CPU的能力,提高效率,降低延迟和阻塞等等。但实际上,触发器程式设计也给他们构筑事物的关系提供了帮助。

在APP初始化中,他们能发现SDK初始化,数据库初始化,登陆接口这三个业务本身相互独立,应当在不同的线程环境中执行,以保证他们不会相互阻塞。而假如没有触发器程式设计,他们可能根本无法在两个线程中顺序调用这三个相对耗时较多的业务,最终再去做页面跳转,这样做不仅没有忠实反映业务本来的亲密关系,而且会让你的程序“反应”更慢。

小结

总的来说,触发器和报文都是为了正确的构筑事物的亲密关系而存在的。只不过,触发器是为了区分出无关的事物,而报文(事件流)是为了联系起有关的事物

APP初始化应该怎么写?

许多采用Rx程式设计的同学可能会采用此种方式来完成APP的初始化。

Observable.just(context)            .map((context)->{login(getUserId(context))})            .map((context)->{initSDK(context)})            .map((context)->{initDatabase(context)})            .subscribeOn(Schedulers.newThread())            .subscribe((context)->{startActivity()})

其实,此种写法并不是积极响应式的,本质上还是创建两个子线程,然后顺序调用标识符最后跳转页面。此种标识符依然没有忠实反映业务之间的亲密关系。

在我心目中,积极响应式的标识符应该是这样的:

Observable obserInitSDK=Observable.create((context)->{initSDK(context)}).subscribeOn(Schedulers.newThread()) Observable obserInitDB=Observable.create((context)->{initDatabase(context)}).subscribeOn(Schedulers.newThread()) Observable obserLogin=Observable.create((context)->{login(getUserId(context))})                              .map((isLogin)->{returnContext()})                            .subscribeOn(Schedulers.newThread()) Observable observable = Observable.merge(obserInitSDK,obserInitDB,obserLogin) observable.subscribe(()->{startActivity()})

大家应该能很明显看到两段标识符的区别,第二段代码完全遵照了业务之间客观存在的亲密关系,可以说标识符和业务亲密关系是完全对应的。

那么这带来了什么好处呢?当initSDK,initDB,Login都是耗时较长的操作时,遵照业务亲密关系编写积极响应式标识符可以极大的提高程序的执行效率,降低阻塞。

理论上讲,遵照业务亲密关系运行的标识符在执行效率上是最优的。

为什么引入积极响应式程式设计

对积极响应式程式设计有了一些了解之后,我知道马上会由许多人跳出来说,不采用这些积极响应式程式设计他们还不是一样开发APP?

在这里我希望你认知一点,当他们用老办法开发APP的时候,其实做了许多妥协,比如说下面的APP初始化业务,三个无关耗时操作为了方便,他们往往就放在两个线程环境中去执行,从而牺牲了程序运行的效率。而且实际开发中,此种类似的业务逻辑还有许多,甚至更加复杂。假如不引入积极响应式的思路,不采用Rx的程式设计模型,他们面对这么些复杂的业务亲密关系真的会很糟心。假如你做一些妥协,那就会牺牲程序的效率,假如你千辛万苦构筑出业务亲密关系,最终写出来的标识符也一定很复杂难以保护。所以,积极响应式程式设计其实是一种更友好更高效的开发方式。

根据个人经验来看,积极响应式程式设计至少有如下好处:

在业务层面实现标识符逻辑分离,方便后期保护和开拓

极大提高程序积极响应速度,充分发掘CPU的能力

帮助开发者提高标识符的抽象能力和充分认知业务逻辑

Rx丰富的运算符会帮助他们极大的简化标识符逻辑

两个复杂一些的例子:

接下来,我就以他们团队现阶段的一款产品的页面为例,详细点介绍运用积极响应式程式设计的正确姿势。

重新理解响应式编程

首先,UI和产品沟通后,可能会给他们这样的设计图(加上一些尺寸的标注)。但他们并不须要急忙编码,他们首先要做的是区分其中相对独立的模块。

重新理解响应式编程

上图我做了一点简单的标注。把那个页面的业务逻辑简单的分为四个相互独立的模块,分别是视频模块,在线人数模块,礼物模块,消息模块。他们相互独立,互不影响。接下来,他们再去分析每个模块内部的业务并构筑起业务之间的亲密关系。大致如下:

重新理解响应式编程

构筑了业务之间的亲密关系图,其实他们的工作已经完成了一半了,接下来是用标识符实现那个亲密关系图。在这里,我就以其中一小段业务亲密关系来编写标识符给大家示范。

重新理解响应式编程

Observable obserDownload=Observable.just(url)                                        .map((url)->{getZipFileFromRemote(url)});    Observable obserLocal=Observable.just(url)                                        .map((url)->{getZipFileFromLocal(url)});    Observable obserGift=Observable.concat(obserLocal,obserDownload)                                        .takeUnitl((file)->{file!=null});    obserGift.subscribeOn(Schedulers.io()).flatMap((file)->{readBitmapsFromZipFile(file)})                                        .subscribe((bitmap)->{showBitmap(bitmap)})

以上是我手写的伪标识符,可能细节上有些难题,但大体思路是这样。

有人可能会说,那是因为你运用运算符比较熟练就可以这么写。其实运算符都是我查的,我记不住那么多运算符,所以基本上我都是先理清楚业务之间的亲密关系,须要和并逻辑的时候,就去去查合并类的运算符,须要条件判断来分流的逻辑时去找条件判断类的运算符。基本上都能满足需求。你瞧,写标识符是这么简单,后续即使须要增加需求,标识符修正起来也很清晰,因为无关的业务已经被你分离好了。

所以,赶紧在你的项目中引入积极响应式程式设计吧!

后记

前几段时间换了工作,在现阶段的团队里除了实现日常需求,也会负责项目重构这一块,我会更多的采用积极响应式的方式重构项目,同时也会尽力在团队内部推动积极响应式程式设计的采用,一旦有了新的体会,我也会在第一时间和大家撷取。

由于这篇该文讲的是积极响应式程式设计,因而更多的采用的Rx那个名称,而不是RxJava,因为RxJava只是积极响应式程式设计在Java语言中的实现。不过里面的伪标识符都是采用RxJava来编写的,希望大家能够认知。

重新理解响应式编程

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务