桥接模式和嵌套lambda表达式

嵌套lambda表达式 :x->y->x+y

 

上课时,我们在策略模式的基础上,介绍了其推广模板方法模式与桥接模式。 n次策略模式

 

  • 2次行为参数化(可变部分)是独立的,则模板方法模式
  • 2次行为参数化(可变部分)是串接的,则桥接模式。参考传统桥接模式【注,链接文章没有抓住桥接模式的本质——在策略中提供策略,而是从避免类型爆炸出发。yqj2065不想修改它了】

 

1.桥接模式

桥接模式将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

2.函数作为返回值

怎样避免在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);

 

3.嵌套lambda表达式

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/柯里化

 

 

你可能感兴趣的:(#,面向对象设计(Java),《编程导论(Java)》道&理,Java,8)