行为参数化

行为参数化

行为参数化是一种开发模式,Lambda只是提供了更简洁的实现方式,让旧版本通过类和接口的实现方式变得更方便罢了。

一. 意义

应对频繁变更的需求:行为参数化意味着可以准备一段代码,并推迟它的执行,比如可以当作参数传递给另一个方法,等到需要时再执行。


二. 旧版本实现行为参数化

如书中苹果集合筛选实例,客户从颜色开始提出需求,再到重量等,每个需求我们都需要实现一个filter。你可能会想,还是有办法只用一个filter的,于是你实现了 filter(List<Apple> inventory, String color, int weight, ...) ,但这并不能根本解决问题,比如需求变更为根据不同场景筛选对应的属性,或是组合多个属性进行复杂查询,又该如何减少重复代码呢?

我们可以对苹果的筛选标准建模,定义一个谓词,返回一个boolean值。

1
2
3
public interface ApplePredicate{
boolean test(Apple apple);
}

所以我们可以根据需求去扩展ApplePredicate的实现,不同的筛选策略就实现对应的代码。

1
2
3
4
5
6
public class AppleHeavyWeightPredicate implements ApplePredicate{
public boolean test(Apple apple){
return apple.getWeight() > 150;
}
}
......

我们把这些不同的策略看作是filter方法的不同行为,这类似于策略设计模式,我们可以封装一些算法,在运行时再去选择一个执行。ApplePredicate就是算法族,AppleHeavyWeightPredicate等就是不同策略。

下一步我们需要filterApples()方法能接收ApplePredicate对象,这就是行为参数化:让方法接受多种行为(策略)作为参数,并在内部使用,来完成不同的行为

1
2
3
4
5
6
7
8
9
public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p){
List<Student> result = new ArrayList();
for(Apple apple : inventory){
if(p.test(apple)){
result.add(apple);
}
}
return result;
}

上述过程中我们已经做到了让filterApples()方法根据我们定义ApplePredicate对象传递的代码来选择行为,实际上就已经做到了行为参数化。

我们发现解决不断变更的需求这一问题时,通过把迭代集合这一行为和筛选逻辑判断行为进行了分离,随着需求而变的行为作为参数传递选择,从而通过重复使用一个方法来应对变化的需求


三. 对行为参数化进行优化

因为filterApples()方法只能接受对象,所以我们传递的代码只能包装在对象中,但Java 8后就可以通过Lambda,直接把apple.getWeight() > 150;这种表达式直接传递给filterApples()方法,而不用构建多个ApplePredicate对象。

3.1 匿名类

熟悉Java的人可能会想到匿名类好像就可以解决重复创建ApplePredicate对象的问题,因为它可以随用随建。

1
2
3
4
5
List<Student> result = filterApples(inventory, new ApplePredicate(){
public boolean test(Apple apple){
return apple.getWeight() > 150;
}
});

但匿名类仍存在一些缺点:1.它不太简洁。2.它让用户觉得难以理解。匿名类虽然解决了为ApplePredicate接口构建实体类的问题,但实际上仍需要创建这些对象,实际上并没有彻底的解决啰嗦的问题。

3.2 Lambda表达式

Lambda表达式的实现如下,彻底解决了啰嗦问题。

1
List<Student> result = filterApples(inventory, (Apple a) -> apple.getWeight() > 150);

行为参数化与值参数化

3.3 泛型

通过泛型进一步抽象,让filterApples()能够适用更多的对象。

1
2
3
4
5
6
7
8
9
public static <T> List<T> filter(List<T> list, Predicate<T> p){
List<Student> result = new ArrayList();
for(T e : list){
if(p.test(e)){
result.add(e);
}
}
return result;
}

参考:

🔗 《Java8实战》