橋接模式和巢狀lambda表示式@yqj2065

yqj2065發表於2016-11-26
橋接模式和巢狀lambda表示式
大家看看,歡迎拍磚。



上課時,我們在策略模式的基礎上,介紹了其推廣模板方法模式與橋接模式。 n次策略模式
2次行為引數化(可變部分)是獨立的,則模板方法模式
2次行為引數化(可變部分)是串接的,則橋接模式。
1.橋接模式

例如對某個int x和y進行某種操作,如x*x + x*y,可以編寫函式

package higherOrderFunction;
import static util.Print.*;
/**
 *
 * @author yqj2065
 */
public class ReturnFunction {
    public static int twoStep(int x, int y) {
        return x*x + x*y;
    }
    public static void main(String[] arg) {
        //使用twoStep(int,int)
        pln(twoStep(2,3));
    }
}
<p class="indent">

假如對某個int x進行某種(由使用者指定)操作,然後加上x*y,則可以編寫函式
public static int twoStep(IntUnaryOperator op, int x, int y) {
return op.applyAsInt(x) + x*y;
}
這裡,對行為x*x加以引數化。顯然,我們可以對+ x*y加以引數化。注意,我們是在IntUnaryOperator op1的基礎上進行第二步操作。
public static int twoStep(IntUnaryOperator op1, int x, IntBinaryOperator op2,int y) {
int i = op1.applyAsInt(x);
int result = op2.applyAsInt(i, y);//橋接模式
//int result = op1.applyAsInt(x)+op2.applyAsInt(x, y) ;//模板方法模式
return result;
}
在這個方法中,能夠清楚地看到模板方法模式與橋接模式的不同。我們在main()中編寫測試程式碼:
pln(twoStep(2,3)); //對於twoStep(int,int),簡單而直觀
int i = twoStep(x -> x * x, 2, 3); pln("1:"+i); //對於twoStep(IntUnaryOperator,int,int),2*2+2*3,也簡單。結果10
橋接模式的twoStep(IntUnaryOperator op1, int x, IntBinaryOperator op2,int y),如何完成上一個測試,結果10呢?
int j = twoStep(x -> x * x, 2,(x,y)->x*x+x*y, 3); pln("2e1:"+j);
錯誤。IntBinaryOperator引數的用法為op2.applyAsInt( op1.applyAsInt(x), y)
正確的lambda表示式為(x,y)->x+2*y:
int j = twoStep(x -> x * x, 2,(temp,y)->temp+2*y, 3); pln("2:"+j);//
其中有一個非常讓人不爽的2,作為x的實參的2,在lambda表示式中要寫出來。再例如
i = twoStep(x -> x * 5, 4, 3); pln("3:"+i); //32
j = twoStep(x -> x * 5, 4,(x,y)->x+4*y, 3); pln("4:"+j);//32


2.函式作為返回值

我們可以將int twoStep(IntUnaryOperator op1, int x, IntBinaryOperator op2,int y)重構為函式介面

package util;
import java.util.function.IntUnaryOperator;
public interface TwoStep {
    int secondOP(IntUnaryOperator firstOP, int x,int y);
}
<p class="indent">

於是,main中的測試程式碼
//使用TwoStep
TwoStep ts = (step1, x,y)->step1.applyAsInt(x)+x*y;
i=ts .secondOP(x -> x * x, 2, 3);pln("3:"+i);
TwoStep能夠很好地完成任務,也避免了在lambda表示式中寫常數的尷尬。
大多數情況下,我們習慣某種資料或實體物件作為返回值。

package util;
import java.util.function.IntUnaryOperator;
public interface MyTwoStep {
    int secondOP(IntUnaryOperator firstOP, int x);    
}
<p class="indent">

MyTwoStep比TwoStep少了引數int y,直接在main中測試時,需要額外提供資料
final int a=3;
MyTwoStep op2 = (firstOP,x) -> firstOP.applyAsInt(x) +x*a;
i = op2.secondOP(x -> x * x,2); pln("4:"+i);
這並不有趣。我們現在定義一個複合操作,

package util;
public interface CompositeOP {
    MyTwoStep op(int y);    
}
<p class="indent">

它提供資料y,並返回一個函式。在main中測試
CompositeOP op1 = (y) -> {return (firstOP,x) -> firstOP.applyAsInt(x) + x*y;};
i = op1.op(3).secondOP(x -> x * x,2); pln("5:"+i);
3.巢狀lambda表示式

CompositeOP op1 = (y) -> {return (firstOP,x) -> firstOP.applyAsInt(x) + x*y;};
的簡化版本:
CompositeOP op1 = y->(firstOP,x) -> firstOP.applyAsInt(x) + x*y;
這種巢狀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);
        int j = twoStep(x -> x * x, 2,(x,y)->x+2*y, 3);        pln("2:"+j);
        j = twoStep(x -> x * x, 2,(x,y)->x*x+x*y, 3);        pln("2e1:"+j);        
        i = twoStep(x -> x * 5, 4, 3);        pln("1-1:"+i);
        j = twoStep(x -> x * 5, 4,(x,y)->x+4*y, 3);        pln("2-1:"+j);
        
        //使用TwoStep
        TwoStep ts = (step1, x,y)->step1.applyAsInt(x)+x*y;
        i=ts .secondOP(x -> x * x, 2, 3);pln("3:"+i);
        //直接使用MyTwoStep        
        final int a=3;
        MyTwoStep op2 = (firstOP,x) -> firstOP.applyAsInt(x) +x*a;
        i = op2.secondOP(x -> x * x,2); pln("4:"+i);   
        //使用CompositeOP 
//        CompositeOP op1 =  (y) -> {return  (firstOP,x) -> firstOP.applyAsInt(x) + x*y;};
        CompositeOP op1 =  y->(firstOP,x) -> firstOP.applyAsInt(x) + x*y;
         i = op1.op(3).secondOP(x -> x * x,2);pln("5:"+i);     
    }
<p class="indent">

10
1:10
2:10
2e1:28
1-1:32
2-1:32
3:10
4:10
5:10

貼程式碼怎麼不行呢??

[該貼被yqj2065於2016-11-26 17:32修改過]

[該貼被yqj2065於2016-11-26 17:33修改過]

[該貼被yqj2065於2016-11-26 17:39修改過]

相關文章