不得不说这是一本好书。本书涉及的主要内容从书名就可以看出来:函数式、响应式、领域驱动建模。
该书并不是一个入门级教材,读者需要对函数式、响应式、领域驱动建模有一定的基础,缺一不可。比如我对领域驱动建模这块不是太熟悉,研读的时候会不太理解作者为什么会举那些例子;对函数式不够深入,看后面几章就会有云里雾里的感觉;对响应式不清楚,就不会明白作者费那么大的劲举的例子解决了一个什么问题。简单点来说,读此书需要把函数式、响应式、领域建模相关知识补充一下。正如AKKA创始人说的那样,“如果内心不够强大,那么这本书将不适合你,阅读它很费劲”。
幸运的是,你看到了这篇博客,作者会在下面的篇幅中简单的介绍函数式、响应式、领域驱动建模的基本概念及其解决的问题,这样你读此书的时候就不会像作者那么吃力了。
- 函数式编程
*对函数式编程的解释:在计算机科学里,函数式编程是一种编程范式,它将计算描述为表达式求值并避免了状态和数据改变。函数式编程几个重要的特性:纯函数无副作用、不变的数据、高阶函数、流计算模式、尾递归、柯里化等。函数式编程中的“函数”可以简单的理解成数学中的函数。学过高等数学的都知道,函数一般定义为:y=f(x),很明显它有几个特点:有至少一个输入,至少一个输出,输入相同时输出相同。
纯函数无副作用是指从业务领域角度来看,函数值仅仅取决于输入(及内部变量),计算过程中没有副作用产生,函数执行多次和执行一次对业务领域产生的作用相同。副作用是指除了返回函数值以外的其他结果,例如修改全局变量。纯函数既不依赖外部的状态也不修改外部的状态。
不变的数据是指变量的值是不可变的。比如命令式编程时,定义一个整型变量x,可以多次赋值动作,例如执行x=1,x=2,x=3,x=4一系列操作之后,x最终值是4。而函数式编程中,变量一旦赋值,则不允许修改。这一点跟高等数学中的代数很像,估计对于数学家来说,1和2是两个不同的变量,是不可以把1和2相互赋值的。
高阶函数就是函数的函数。简单点来说就是,输入是一个函数,输出也是一个函数。在数学中它们也叫做算子(运算符)或泛函。函数是对自变量的映射,高阶函数是对函数的映射。
流计算模式其实就是pipeline,使用它可以让代码具有申明式的语义化、模块化,更加富有表现力。例如下段代码:
getStock() .filter(quote => quote.price > 80) .map(quote => quote.price) .foreach(price => console.log(`Prices higher than $30: ${price}`));
尾递归就是函数尾部调用自身。既然函数编程中变量不可变,那怎么实现循环呢,毕竟循环需要有一个计数器的,函数式语言里面只能用递归来解决迭代问题。但递归会造成栈溢出的问题,那么尾递归可以解决这个问题,编译器会在编译期间会将尾递归优化为循环,从而解决栈溢出的问题。
柯里化就是一个函数在参数没给全时返回另一个函数,返回的函数的参数正好是余下的参数。curry化最大的意义在于把多个参数的function等价转化成多个单参数function的级联,这样所有的函数就都统一了,方便做lambda演算。 在scala里,curry化对类型推演也有帮助,scala的类型推演是局部的,在同一个参数列表中后面的参数不能借助前面的参数类型进行推演,curry化以后,放在两个参数列表里,后面一个参数列表里的参数可以借助前面一个参数列表里的参数类型进行推演。这就是为什么 foldLeft这种函数的定义都是curry的形。
关于函数式编程可参考 什么是函数式编程思维
响应式编程
响应式编程更像是一种设计思想或者设计目标。响应式编程的目标通常是程序或应用具有响应能力:可相应的、弹性、伸缩性、消息驱动。弹性是面对失败的相应;伸缩性是在不同负载情况下的响应;消息驱动是指松耦合性,通过异步消息隔离上下文。响应式编程最重要的思想就是围绕失败来做设计,并提升模型的综合弹性。按照我的理解响应式模型一定是有响应的,不管是正常的还是异常的,当然这一点仁者见仁智者见智。响应式编程是一种关于数据流和变化传播的声明式编程范例,简单点来说就是程序对异步事件进行相应的处理。
关于响应式编程可参考 那些年我们错过的响应式编程
领域驱动建模
领域驱动设计(DDD)是一种软件设计思想,是在软件开发时对现实世界进行抽象并映射到软件系统的方法论。这在设计大型软件或系统时非常重要的设计方法,当然了,如果你只是写一个排序函数就没必要这么大费周章了。由于作者对DDD不太熟悉,只能谈一下个人的简单感受:DDD是一套软件设计方法论,它采用实体、值对象、模块、聚合、工厂、仓库等基本概念指导如何对现实世界中的业务进行建模。
对于DDD可参考 浅析DDD(领域驱动设计)