什么是行为参数化

行为参数化是使方法接受多种行为作为参数,并在内部使用,完成不同的行为。行为参数化可让代码更好地适应不断变化的要求,减轻未来的工作量,是可以帮助你处理频繁变更的需求的一种软件开发模式。

需要指出的是,行为参数化不是Java8的新特性,但是是Java8新特性的重要基础和思想。

举例解释:假设有这样一个场景,小明开车去超市买东西,我们可以定义一个goAndBuy()方法。但针对另一个场景,小明开车去医院挂号或者去动物园看猩猩,使用goAndBuy方法显然是不正确的。如果我们定义go方法,将买东西、挂号、看猩猩等不同行为作为参数,送给go方法执行,则能够很好地适应新场景。

理解行为参数化的经典案例–苹果的故事

案例中不断变换需求,使得不得不重构代码应对新的变化。

1 定义苹果对象类

public static class Apple {

private int weight; // 重量
private String color; // 颜色

public Apple(int weight, String color) {
    this.weight = weight;
    this.color = color;
}

public Integer getWeight() {
    return weight;
}

public void setWeight(Integer weight) {
    this.weight = weight;
}

public String getColor() {
    return color;
}

public void setColor(String color) {
    this.color = color;
}

@Override
public String toString() {
    return "Apple{" + "weight=" + weight + ", color='" + color + '\'' + '}';
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2 根据颜色筛选苹果

public static List filterGreenApples(List inventory) {
List result = new ArrayList<>();
for (Apple apple : inventory) {
if ("green".equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}

List greenApples = filterGreenApples(inventory);
1
2
3
4
5
6
7
8
9
10
11
针对于苹果存货列表inventory,我们做遍历操作,轻而易举地获取到绿色苹果列表。此时,修改需求转为选出绿色苹果,我们会修改上述方法:

public static List filterApplesByColor(List inventory, String color) {
List result = new ArrayList<>();
for (Apple apple : inventory) {
if (apple.getColor().equals(color)) {
result.add(apple);
}
}
return result;
}

List redApples = filterApplesByColor(inventory, "red");
1
2
3
4
5
6
7
8
9
10
11
通过添加color形参,解决了不同颜色水果的问题。然而Apple类有多个属性,此时需求改成按照苹果重量筛选,以及按照苹果颜色和重量筛选,上面的方法便不能很好的应对,也容易造成代码的冗余。

public static List filterApplesByWeight(List inventory, int weight) {
List result = new ArrayList<>();
for (Apple apple : inventory) {
if (apple.getWeight() > weight) {
result.add(apple);
}
}
return result;
}

List weightBiggerThan120Apples = filterApplesByWeight(inventory, 120);
1
2
3
4
5
6
7
8
9
10
11
3 使用匿名内部类进行优化

显而易见,方法代码中存在大量重复代码,唯一不同的便是筛选条件不同。我们将筛选这一行为,从filterApples方法中单独取出。

定义筛选条件接口

public interface ApplePredicate {
boolean test(Apple apple);
}
1
2
3
同时继续修改过滤函数

public static List filterApples2(List inventory, ApplePredicate predicate) {
List result = new ArrayList<>();
for (Apple apple : inventory) {
if (predicate.test(apple)) {
result.add(apple);
}
}
return result;
}
1
2
3
4
5
6
7
8
9
方法调用

List heavyApplesByAnonyInnerClass = filterApples2(inventory, new ApplePredicate() {br/>@Override
public boolean test(Apple apple) {
return "green".equals(apple.color) && apple.getWeight() > 150;
}
});
1
2
3
4
5
6
我们将筛选条件行为作为形参传给了过滤方法,此时,针对于Apple筛选的各种需求,上面的代码都可以满足。这一过程即是行为参数化:让方法接受多种行为做参数,并表现出不同目的。行为参数化,很好的将迭代整个Apple列表的操作与针对每个Apple元素的操作做了解耦,从而能够重复使用同一个方法,给予不同行为参数,获取不同目的。

行为参数化与策略模式息息相关,定义一系列算法,将它们封装起来,并且使他们可相互替换。本小节使用的是匿名内部类,如果传入的是实现类,可以更加直观的理解策略模式的使用。

4 使用Lambda表达式继续优化

匿名内部类优于具体实现类,但仍然很笨重,并且易读性差。因为我们有更好的解决方案–使用Lambda表达式,清晰易读,代码量少。

List heavyApplesLambda = filterApples2(inventory, apple -> "green".equals(apple.color) && apple.getWeight() > 150);
1
深圳网站建设www.sz886.com