GOF提出的设计模式,其本质思想是封装变化。故而,建立型模式封装的是对象建立的变化,结构型模式封装的是对象之间的协做与组合结构,行为型模式则封装了对象行为的变化。所谓“行为”,不正是函数所能要表达的吗?在支持FP的编程语言中,函数成为了一等公民,即它能够脱离对象而单独存在,也可以当作参数或返回值(高阶函数)。因而,传统的OO设计模式开始了变化,尤为是行为型模式。java
从函数的抽象角度看,任何行为均可以理解为是一个对类型进行转换的函数,这是FP思想对OO设计模式的最大冲击。例如Strategy模式与Command模式,前者封装了算法策略的变化,后者则封装了命令请求的变化。不管算法策略,仍是命令请求,均可以表现为一个函数。程序员
譬如说将各类四则运算看作是一种算法策略,为了应对具体计算的变化,在Java中咱们应该定义四则运算的策略接口:算法
public interface Strategy {
int compute(int a, int b);
}
public class Context {
private final Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void use(int a, int b) {
strategy.compute(a, b);
}
}复制代码
接收两个整数,而后通过计算返回一个整数。显然,四则运算的调用者其实关注的不是Strategy
这个接口,而是compute
这个行为。跟进一步,调用者其实关注的是将两个整数转换为一个整数的行为,他并不关心接口是什么,函数名有是什么,而是关注f(a, b) = c
这个函数。因而,在Scala中,策略模式的实现就变为:编程
class Context(f: (Int, Int) => Int) {
def use(a: Int, b: Int): Int = f(a, b)
}复制代码
固然,你能够能够为这个函数定义一个类型,使其更加表意:设计模式
type Stategy = (Int, Int) => Int复制代码
固然,若是面对的是一组策略行为的封装,且这些策略行为的变化是一致的,使用一个接口将这些行为封装起来,在重用和表意角度讲,彷佛又比单纯使用函数更佳。Scala提供OO与FP两种范式,算是一种骑墙的取巧,程序员须要依势而为。Scala给你提供了丰富而精彩的食材,若是你没有将菜作得色香味俱全,不能怪食材很差,仍是本身太烂了。编程语言
Scala还提供了一种相似block的机制,称之为by name call。它接受的是一个语句块,而非函数类型。因此要注意这种形式与无参函数的区别。此外,by name call同时还具备延迟调用的能力。例如,当咱们定义一个invoke
函数接受一个无传入参数的函数时:函数
def invoke(f: () => Unit) = f()复制代码
若是你向invoke
传入println("scala")
,scala会报告错误:post
这是由于println("scala")
返回的是Unit
类型,而不是() => Unit
函数类型。使用by name call就没有这个问题:this
f: => Unit
是一个语句块,因此不能像函数那样调用。咱们可使用这种方式来快捷实现Command模式。spa
因为Java 8已经支持Lambda表达式,虽然它仍然不支持高阶函数,可是做为Java程序员,仍然有必要培养函数抽象的能力与习惯。在Java 8中使用Lambda,不只让语法变得简洁,还可让调用者能够脱离对具体某个接口的依赖,而仅仅依赖函数的抽象特征。
FP的编程思想中,除了高阶函数(包括Curry等)具备的抽象能力以外,还有一个好处是提供组合子能力。落实到Scala的语法上,就是偏函数(Partial Function)的andThen
,compose
与orElse
。
Pavel Fatin在文章《Design Patterns in Scala》用OO设计模式中的Chain of Responsibility(职责链)模式来对比组合子,其实仍是比较牵强的。或者说,FP思想中的组合子远远比职责链模式更强大。在Elixir语言中,甚至还提供了管道操做符|>
实现这种函数的组合。而我在博客《Scala中的Partial Function》中已经很是详解地介绍了Scala的偏函数,你们能够移步阅读。
若是真要对比,那么结合Scala的语法来看,则orElse
能够很是方便地模拟职责链模式,而andThen
则近似于管道-过滤器模式。其实我在OO语言中,不多运用GOF标志的职责链模式,也就是当寻找到具体职责的承担者时,履行职责后便可退出的方式;而是对这种模式进行调整,让其在履行职责后继续执行next
的职责,又近乎于管道-过滤器了。
因此说,设计模式的运用妙乎于心,讲究应势而变。在融入FP思想后,要从本质思想去面对这些模式,不拘泥于OO仍是FP,彷佛才是将来编程的取舍之道。