前言
UniRx,顾名思义就是Unity上的ReactiveX(Rx)。Unity就很好理解了,可是这个Rx又是哪路神仙?找到Rx的官方简介,大概意思是:ReactiveX是一个通过可观察序列来综合异步编程和事件编程的库。
这句话回答了很多问题:首先它是一个库,其次它的作用是简化异步编程和事件编程,使用的手段是可观察序列。
于是,我们现在已经对Rx有了一个比较模糊的认识,现在我们再来看看UniRx的官方定义:UniRx(Reactive Extensions for Unity)是.Net Reactive Extensions(Rx.Net)的一个重新实现,因为Rx.Net不兼容Unity和iOS。这个库修复了Rx.Net的一些Bug,增加了一些针对Unity的功能,并且支持更多的平台。
综上所述,我们可以这么理解:UniRx是在Unity上实现的增强版Rx。
鉴于面向对象是当下的主流,在开始之前,给你一点忠告:
请暂时忘掉面向对象的思维模式。
请暂时忘掉面向对象的思维模式。
请暂时忘掉面向对象的思维模式。
响应式编程
在具体介绍UniRx之前,需要先引入一个新的编程范式——响应式编程(RP),一种和面向对象有异曲同工之妙的思维模式。在这里,所有东西都是数据流,数据流之间可以通过相互观察来建立依赖关系,从而相互协作,完成工作。这里的观察的语义和观察者模式里的观察相同,RP本身甚至都可以视为观察者模式的一种高阶形态。
乍一看RP和OOP很相似,好像只是换了一套术语而已。可是,当我们细品这些术语时,就会发现:RP怎么这么反人类???关系全都是反的。在OOP中,A依赖B的含义是:A调用B;而在RP中,当A观察B时,反而是B调用A。在OOP中我们讲究依赖倒置,上层模块不应该依赖下层模块而应该依赖抽象;而在RP中根本就没有“抽象”这个概念,具体的数据流之间明显存在着依赖关系。
以上这些事实让我们意识到一个严重的问题:RP和OOP虽然表面上很像,但内在的区别可远不止换了一套术语这么简单,非常容易混淆。所以我说在学习RP之前一定要摒弃OOP,有意识地将这两种思维模式隔离开来,否则你真的会走火入魔的。
OOP和RP的根本区别在于看问题的方式不同。OOP中的对象更像一个领导,大多数对象不会去接触底层工作,只是想着谁能完成工作我就去找谁。所以对象看问题的方式是:我找谁。而RP中的数据流大多本身就有业务逻辑,所以数据流更关心如何推销自己,谁需要我的功能我就去告诉他可以帮他。所以数据流看问题的方式是:谁找我。
这两种方式其实并没有优劣之分,它们的目标是相同的:通过让软件的行为更符合人类的思维来降低软件开发的难度。在现实中,根据情境不同,确实有时候需要侧重我找谁,有时候需要侧重谁找我。你口渴了总不能等着水自己飞到你嘴里去吧,你要么自己去找水(依赖查找),要么让别人给你拿水来(依赖注入)。无论如何,你想的都是我找谁。但是在求职的时候就不同了,你会向企业推销自己,告诉他们你有能力胜任工作,当他们缺人手的时候就来找你。在这种情况下,你想的就是谁找我。
可观察序列
说了这么多,也该回到正题了。根据Rx的定义,我们不难发现它就是一个响应式编程环境。上面也说了,有些问题对于OOP来说非常棘手,而RP存在的意义,正是弥补OOP在这些场景中缺陷。
我以一个简单的小练习开头:实现一个函数,用户每次双击左键就在控制台打印一个1。
这是传统的OOP(或者说POP)实现:
public class DoubleClick : MonoBehaviour
{
private float time; // 距离上一次点击的时间
private float threshold