责任链模式,十分常见,比如说,j2ee里的filter,express里的middleware,redux里的middleware
问题是:怎么才可以用最简单的方式实现一个责任链模式?
用数组,链表来记录中间件?这些都想过,后来终于找到一种很简单的方式,灵感来自于fp
使用者要的是什么
对于使用者来说,Middleware应该是不可见的,他们想要的只是最后的结果,也就是一个普通的函数:
input => output
所以,先定义一个Function接口来表示:
public interface Function {
Object apply(Object input);
}
Middleware是什么
这个middleware最后抽象出来的样子,会决定我们后面的实现方式
Middleware跟Function的区别在于,Middleware除了能拿到input,它还能拿到"下一站"的Function
所以,middleware应该是一个能对Function进行AOP增强的东西:
(input, Function) => output
public interface Middleware {
Object apply(Object input, Function f);
}
将Middleware结合到Function
最后,我们要实现一个结合函数:
(oldFunction, Middleware) => newFunction
就是说,给你一个oldFunction和一个Middleware,要返回一个newFunction,就是oldFunction通过Middleware增强以后的东西
这个newFunction,可以直接交给用户使用,又或者,可以继续给它增加Middleware
public static Function combine(final Function f, final Middleware mid) {
return new Function() {
public Object apply(final Object input) {
return mid.apply(input, f);
}
};
}
可以看到,input是先流进Middleware的,然后里面干什么,就由这个Middleware决定了。
这样子,责任链就完成了,20行不到的代码。
public class Chain {
public interface Function {
Object apply(Object input);
}
public interface Middleware {
Object apply(Object input, Function f);
}
public static Function combine(final Function f, final Middleware mid) {
return new Function() {
public Object apply(final Object input) {
return mid.apply(input, f);
}
};
}
}
与管道模式对比
FP是好东西,去掉了OO里面那些包装的概念,思考的时候会更简单直接。
管道模式,也就是unix里面CLI程序串接起来的模式,对应到fp,其实就是最简单的函数组合
h(x) | g | f 其实就是 f(g(h(x)))
将责任链模式 与 管道模式 对比,会发现,能力上,责任链是完胜管道的,因为责任链实际上是对Function的AOP增强,这种增强,可以是同时包含了前置的和后置的。
而管道模式的增强,只能是前置的(或者后置的)。
管道模式 : (Function, Function) => Function
责任链模式 : (Function, Middleware) => Function