模式和函数式编程可以通过两种方式结合在一起.
首先,对于很多面相对象的设计模式来说,采用函数式编程实现会更加简单,因为函数式语言为我们提供了更加简洁的方式来完成一些值的传递,而无需创建新的类.使用表达式(expression)而非语句(statement)可以让我们消除那些额外的变量.并且,声明性是那些函数式解决方案所拥有的特质,这种特质可以让我们在一行代码中完成原本在命令式语言中需要五行代码才能完成的工作.我们甚至可以用函数式语言特性的应用来代替那些面向对象模式.
其次,函数式世界也有一套自己的有用的模式.这些模式专注于编写避免可变性且偏好声明性风格的代码,可以帮助我们编写出更加简单且已维护的代码.
什么事函数式编程
函数式编程拥有以下特征:
- 拥有头等函数: 头等函数是指那些可以被传递,动态创建,并且可以存储于数据结构的函数.可以在语言中像处理其他对象一样对他们进行处理.
- 偏好纯函数: 纯函数是指那些没有副作用的函数.副作用是指函数的某种行为,这种行为会对函数之外的状态进行修改.
- 组合函数: 函数式编程支持通过将函数进行组合来自底向上的构建程序.
- 使用表达式: 函数式编程偏爱表达式胜过语句.表达式会产生值,而语句则不会,他的存在仅仅是为了控制程序的执行流程.
- 使用不变性: 因为函数式编程偏爱纯函数,而纯函数不会修改数据,它同时又使用了大量不可变数据.所以程序不会去修改一个已经存在的数据结构,而是有效的创建一份新数据.
- 转换数据而非修改数据: 函数式编程使用函数来转换数据.将一个数据结构输入函数,然后输出一个新的不可变数据结构.这与流行的面向对象模型产生了明显的对比,后者将对象视为对可变状态和行为的小型封装.
模式词汇表
替代面向对象模式
替代函数式接口
采用原生的函数式特性替代像Runnable和Comparator这样常见的函数式接口.
这一部分引入了两个基本的函数式特性:
- 高阶函数: 允许我们将函数作为头等数据进行传递.
- 匿名函数: 允许我们编写便捷的一次性函数,而无需为其制定函数名.
替代承载状态的函数式接口
我们采用这种模式来替代那些需要承载某些状态信息的函数式接口实例,为此我们引入了一个新的函数式特性:闭包.闭包可以将某个函数的某些状态打包传递.
替代命令模式
替代命令模式将行为封装于某个对象当中,我们将了解如何使用在前两种模式中介绍的技术来代替面向对象版本中的命令模式.
替代生成器模式来获得不可变对象
通常我们采用传统的Java约定(即一个具备setter和getter方法的类)来承载数据,但是这种方式却与可变性紧密相连.这一模式中我们将展示如何从得益于不变性的JavaBean中获取便利.
替代迭代器模式
替代迭代器模式让我们以顺序的方式访问集合子项,我们将会看到如何采用高阶函数和序列推导来解决我们原本采用迭代器模式所解决的诸多问题,这些技术给我们带来了更具声明性的解决方案.
替代模板方法模式
这一模式定义了基类中的算法轮廓,而算法的具体细节留给子类来实现.这一模式中我们将看到如何采用高阶函数和函数组合来替代这一基于继承的模式.
替代策略模式
这一模式中,我们定义了一组都实现了某个共同接口的算法.这让程序员可以将一种算法实现替换成另一种算法实现.
替代空对象模式
这一模式中我们讨论了如何去替换空对象,同时也对null的其他处理方式进行了探讨.
替代装饰器模式
替代装饰器模式可以为对象增加新的行为而不改变其原有的类.这一模式中,我们将看到如何使用函数组合来达到相同的效果.
替代访问者模式
替代访问者模式使得为某种数据类型添加操作变得简单,却难以为类型添加新的实现.
替代依赖注入
该模式可以像某个对象注入其依赖,而非内联的实例化这些依赖,这样做将允许我们对这些依赖的实现进行替换.
函数式模式介绍
尾递归模式
尾递归从功能上来说与循环等效,但是他提供了一种编写递归算法的特殊方式,这种方式避免的每次递归调用都消耗栈帧.
相互递归模式
相互递归是一种递归函数相互调用的模式.和尾递归一样,我们需要为相互递归找到一种切实有效的方式来避免栈帧的消耗.
FilterMapReduce模式
filter,map,reduce,使我们最常用的三个高阶函数.通过将他们组合在一起使用,我们便得到了一个非常强大的数据处理工具.
操作链模式
函数式编程通常会避免可变性,所以为了避免对某个数据结构进行修改,我们通常会选择一个不可变的数据结构,并对该结构进行操作,然后产生一个新的数据结构.
函数生成器模式
高阶函数可以使用函数生成器模式来创建其他函数.
记忆模式
该模式通过缓存函数调用结果来避免对昂贵计算的重复执行.
惰性序列模式
惰性序列是这样一种模式: 序列中的元素只有在需要时才被实例化.这允许我们创建一个无限场的序列,从而能简单的处理数据流.
集中的可变性
集中的可变性可以通过在程序中的一小段关键性代码是使用可变数据结构来优化性能.对该模式的需求远比你想象中的罕见.
自定义控制流
对于大多数语言而言,通常无法再不修改语言本身的情况下向语言添加新的控制流.
领域特定语言
领域特定语言模式允许我们创建一种专用语言来解决特定的问题.