行为参数化/策略模式 && Lambda表达式

这篇文章不涉及Lambda表达式的具体使用,只谈谈我对其的一些理解。不一定对,如有偏颇,望指正。


行为参数化/策略模式

Java是一门面向对象的语言。

奉行一切皆对象,需要什么就把这个他当作对象传递进来。不过有一个东西Java不能直接将其作为对象——方法。

这里的方法可不是Java反射中的Method类。举个栗子~

有个方法需要传入两个Int,一个计算的方法,最后输出计算的值。我们也不知道这个方法会有哪些可能的行为,所以也不能定义一个类与现实中的+-*/方法一一对应。

这时候我们就会想起设计模式中的策略模式

定义一个接口,里面一个运算方法。

1
2
3
4
5
6
7
8
9
class CalTest<T>{
public interface Calculation<T> {
T onCalculate(int a,int b);
}

public T calculate(int a,int b,Calculation<T> cal){
return cal.onCalculate(a, b);
}
}

需要使用的时候传入这个接口的具体实现即可。

1
2
3
4
5
6
7
CalTest calTest = new CalTest();
calTest.calculate(1, 2, new CalTest.Calculation() {
@Override
public Object onCalculate(int a, int b) {
return a+b;
}
});

通过这种模式,我们相当于将Calculation中的onCalculate方法传递了。

这是一个历史悠久的变通方案,很长一段时间我们都是这么写的。

虽然我们不能传递方法,我们可以将方法通过接口的方式“实例化”,将这个方法当作一个对象传到了另一个方法中去。这也就是所谓的行为参数化


Java中的Lambda表达式

Java1.8中,新增加了Lambda表达式。主要是针对以上匿名类的方式“实例化”接口的时候,可以进行简写。

以上代码可改为:

1
calTest.calculate(1, 2, (a, b) -> a+b);

实际上Lambda表达式就是对通过接口实现的匿名类的一种简写。没有任何特别的新功能,Lambda能实现功能不用Lambda也能实现,不用Lambda实现不了的功能用Lambda也实现不了。

于是乎,你也可以将这整个Lambda表达式视作一个行为,它同样可以作为参数进行传递。

Kotlin中的Lambda表达式

Kotlin中的Lambda和Java又不太一样。或者说看上去一样,实际是不一样的。

Kotlin中是有一个专门的写法来表示“方法或行为”这种对象的。

比如以上的例子中,我们需要传入一个“输入两个Int,返回一个泛型类T的方法/行为”这样一个行为对象

Kotlin中就是用(a:Int,b:Int) -> T来表示。所以以上代码用Kotlin的写法为:

1
2
3
fun<T> calculate(a: Int,b: Int,cal:(a:Int,b:Int) -> T){
cal.invoke(a,b);
}

使用起来这样写:

1
2
3
4
5
calculate(1,2,fun(a,b){
//kotlin中直接取最后一行的计算结果作为返回值。
//所以千万别加return,否则返回的结果就成了“return xx"而会直接把最外层return掉了
a+b
})

当然,用Lambda表达式的形式来写,就是这样。

1
2
3
calculate(1,2,{a: Int, b: Int ->
a+b
})

Lambda自带有类型推断功能,所以传入的Int也可以不要。

另外,如果这个LambdaKotlin函数中的最后一个对象,Lambda表达式还可以再简化一点,写到括号外面:

1
2
3
calculate(1,2) { a, b ->
a+b
}

如果这个LambdaKotlin函数中唯一的一个对象,括号也可以去了;

如果这个Lambda是单参数的,参数也可以不加,默认为it。

例如Android中的:

1
2
3
view.setOnClickListener{
it//view
}

所以,Kotlin中的Lambda 和 Java8 中的Lambda 是不一样的:Java8中的Lambda只是一种便捷写法,而kotlin中的Lambda是实实在在的对象

参考:

扔物线的b站

代码真香系列