响应式和函数式,两个容易混淆的概念

响应式(Reactive Programming,简称RP)

在计算机中,响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。

传统的编程方式,是顺序执行的,上一个任务没有完成的话需要等待直至完成之后才会执行下一个任务。无论是提升机器的性能还是代码的性能,本质上都需要依赖上一个任务的完成。如果需要响应迅速,就得把同步执行的方式换成异步,方法执行变成消息发送。这变成了异步编程的方式,它是响应式编程的重要特性之一。

响应式编程有以下几个特点:

  • 异步编程:提供了合适的异步编程模型,能够挖掘多核CPU的能力、提高效率、降低延迟和阻塞等。
  • 数据流:基于数据流模型,响应式编程提供一套统一的Stream风格的数据处理接口。和Java 8中的Stream相比,响应式编程除了支持静态数据流,还支持动态数据流,并且允许复用和同时接入多个订阅者。
  • 变化传播:简单来说就是以一个数据流为输入,经过一连串操作转化为另一个数据流,然后分发给各个订阅者的过程。这就有点像函数式编程中的组合函数,将多个函数串联起来,把一组输入数据转化为格式迥异的输出数据。

响应式编程一方面在用户界面编程领域以及基于实时系统的动画方面都有广泛的应用。另一方面,在处理嵌套回调的异步事件,复杂的列表过滤和变换的时候也都有良好的表现。

现在的App无论是H5、原生还是Hybird,都会和与数据事件相关的 UI 事件进行大量地交互,使用响应式编程会显得更加得心应手。

这些年来前端比较流行的响应式设计,实际上它是指网页能够自动调整布局和样式以适配不同尺寸的屏幕。跟我们这里谈论的响应式编程是两个概念。

函数式(Functional Programming,简称FP)

In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data.

随着硬件能力不断提升,单核CPU的计算能力几乎达到了极限,CPU进入了多核时代,程序员转而通过并发编程、分布式系统来应对越来越复杂的计算任务。

然而并发编程并不是银弹,做为一种基于共享内存的并发编程,多线程编程有常见的死锁、线程饥饿、race condition等问题,而且多线程的bug难以重现和定位。

于是,函数式编程开始兴起。在函数式编程中,由于数据全部都是不可变的,所以没有并发编程的问题,是线程安全的。它将计算机运算看做是数学中函数的计算,主要特点是将计算过程分解成多个可复用的函数,并且避免了状态以及变量的概念。函数式编程虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算。

函数式编程的特点:

  • 函数是"第一等公民":所谓"第一等公民"(first class),指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。
  • 闭包和高阶函数:闭包是起函数的作用并可以像对象一样操作的对象。与此类似,FP 语言支持高阶函数。高阶函数可以用另一个函数(间接地,用一个表达式) 作为其输入参数,在某些情况下,它甚至返回一个函数作为其输出参数。这两种结构结合在一起使得可以用优雅的方式进行模块化编程,这是使用 FP 的最大好处。
  • 递归: 用递归做为控制流程的机制。例如在Haskell的世界中,没有变量赋值,流程跳转,如果要实现一些简单的功能,比如求一个数组中的最大值,都需要借助递归实现。
  • 惰性求值(Lazy Evaluation): 它表示为“延迟求值“和”最小化求值“。惰性求值使得代码具备了巨大的优化潜能。支持惰性求值的编译器会像数学家看待代数表达式那样看待函数式编程的程序:抵消相同项从而避免执行无谓的代码,安排代码执行顺序从而实现更高的执行效率甚至是减少错误。 惰性求值另一个重要的好处是它可以构造一个无限的数据类型,无需要担心由无穷计算所导致的 out-of-memory 错误。
  • 没有"副作用"(side effect):指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。函数式编程强调没有"副作用",意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。

既然函数式编程已经能够解决并发的问题,为何还需要响应式编程呢?

函数响应式(Functional Reactive Programming,简称FRP)

函数响应式结合了函数式和响应式的优点,把函数范式里的一套思路和响应式编程合起来就是函数响应式编程。

我们知道,传统的面向对象编程通过抽象出的对象关系来解决问题。函数式编程通过function的组合来解决问题,响应式编程通过函数式编程的方式来解决回调地狱的问题。

用传统的面向对象来处理异步事件不是很直观,处理并发也是件麻烦的事情,所以才产生了函数响应式编程。

小结

函数式编程和响应式编程是两个不同的概念,刚接触RxJava那会我也经常搞混两者的概念。

两者的结合函数响应式编程确实是给开发带来了一种新的方式和思维上的突破。

参考资料:

  1. http://nicholas.ren/2015/06/24/lets-talk-about-reactive.html
  2. http://emacoo.cn/backend/reactive-overview/
  3. http://www.cnblogs.com/kym/archive/2011/03/07/1976519.html
  4. http://www.ruanyifeng.com/blog/2012/04/functional_programming.html
  5. http://janfan.cn/chinese/2015/05/18/functional-programming.html
  6. https://baike.baidu.com/item/%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/4035031

推荐阅读更多精彩内容