嵌套lambda表达式 :x->y->x+y
上课时,我们在策略模式的基础上,介绍了其推广模板方法模式与桥接模式。 n次策略模式
桥接模式将2次以上的策略选择串接起来形成大策略。例如twoStep(int x, int y) ,对参数int x和y进行特定的多项式操作,如x*x + x*y。现在将twoStep(int x, int y)对计算分成两步,1.仅仅处理x的那些项,2.处理x,y的项,与第一步的结果相加。
仅仅处理x的那些项,抽象为接口F;处理x,y的项,,抽象为接口F2.
package chap4.bridgeP.bridgeP2;
public interface F{
public abstract int f(int x);
}
public interface F2{
int f(int x, int y);
}
package chap4.bridgeP.bridgeP2;
import static yqj2065.util.Print.pln;
public class Demo{
public static int twoStep(int x, int y) {
return 2*x + x*x + x*y;
}
//对于仅仅涉及x的项参数化
public static int twoStep(F f,int x, int y) {
return f.f(x) + x*y;
}
public static int twoStep(F f,int x, F2 f2 ,int y) {
int result =f2.f(f.f(x),y); //桥接模式
//result= f.f(x) + f2.f(x,y); //模板方法模式
return result;
}
public static void main(String[] arg) {
//使用twoStep(int,int)
pln(twoStep(2,3));
int i = twoStep(x -> x * x, 2, 3); pln("1:"+i);
int j = twoStep(x -> x * x, 2,(x,y)->x*x+x*y, 3); pln("2e1:"+j);//错误的用法
}
}
Demo中twoStep(int x, int y)属于硬编码,操作2*x + x*x + x*y;twoStep(F f,int x, int y)中仅仅处理x的那些项被F参数化,而+ x*y属于硬编码。
twoStep(F f,int x, F2 f2 ,int y)试图对两部分参数化,现在的难点是,实现中f2.f(f.f(x),y)不好用!因为f2对象以仅仅处理x的那些项的结果和y为参数,在main中为 F2提供实参时,希望编写(result,y) ->result+x*y,但是x在哪里?如果要获得正确的结果,需要把twoStep(F f,int x, F2 f2 ,int y)的第二个实参即2,写到lambda表达式中。
int j = twoStep(x -> x * x, 2,(result,y)->result+2*y, 3),
再例如
j = twoStep(x -> x * 5, 4,(x,y)->x+4*y, 3); pln("4:"+j);//32
怎样避免在lambda表达式中抄写第二个参数的尴尬?一种方案是对F2进行改造,希望编写(result,y) ->result+x*y,ok,提供一个三参数的接口,F first, int x用于计算result,int x,int y用于计算x*y。
package chap4.bridgeP.bridgeP2;
public interface TwoStep{
int firstStep(F first, int x,int y);
}
//main
TwoStep op = (step1, x,y)->step1.f(x)+ x*y;
j = op.firstStep(x -> x * x, 2, 3); pln("3:"+j);
大多数情况下,我们习惯某种数据或实体对象作为返回值。现在为TwoStep提供一个简化版,比TwoStep少了参数int y,在main中要像TwoStep op = (step1, x,y)->step1.f(x)+ x*y;创建对象,需要在lambda外额外提供数据。这并不是正确使用FirstResult的姿势,我们的目的是把FirstResult作为闭包。
public interface FirstResult{
int op(F f, int x);
}
public interface Bridge{
FirstResult op(int y);
}
//main
final int y=3;
FirstResult op2 = (f,x) -> f.f(x) +x*y;
i = op2.op(x -> x * x,2); pln("4:"+i);
Bridge twoStep = (b) -> {
return (firstOP,a) -> firstOP.f(a) + a*b;
};
i = twoStep.op(3).op(x -> x * x,2);pln("5:"+i);
twoStep = b ->(firstOP,a) -> firstOP.f(a) + a*b;
i = twoStep.op(3).op(x -> x * x,2);pln("6:"+i);
Bridge twoStep = (b) -> {
return (firstOP,a) -> firstOP.f(a) + a*b;
};
的简化版本:
twoStep = b ->(firstOP,a) -> firstOP.f(a) + a*b;
这种嵌套lambda表达式反映了桥接模式的本质——串接的行为参数化。
附:main
public static void main(String[] arg) {
//使用twoStep(int,int)
pln(twoStep(2,3));
int i = twoStep(x -> x * x, 2, 3); pln("1:"+i); //x*x + x*y = 10
int j = twoStep(x -> x * x, 2,(result,y)->result+2*y, 3); pln("2e1:"+j);
TwoStep op = (step1, x,y)->step1.f(x)+ x*y;
j = op.firstStep(x -> x * x, 2, 3); pln("3:"+j);
final int y=3;
FirstResult op2 = (f,x) -> f.f(x) +x*y;
i = op2.op(x -> x * x,2); pln("4:"+i);
Bridge twoStep = (b) -> {
return (firstOP,a) -> firstOP.f(a) + a*b;
};
i = twoStep.op(3).op(x -> x * x,2);pln("5:"+i);
twoStep = b ->(firstOP,a) -> firstOP.f(a) + a*b;
i = twoStep.op(3).op(x -> x * x,2);pln("6:"+i);
}
1:10
2e1:10
3:10
4:10
5:10
6:10
参考:Scheme高阶函数之函数作为返回值暨currying/柯里化