行为参数化

假设有如下业务:有一堆有颜色和重量的苹果,我需要通过颜色和重量取出相应苹果
定义苹果

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
32
public class Apple {
private int weight = 0;
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;
}

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

假设

1
2
inventory = Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120, "red"));

解决方案1:

1
2
3
4
5
6
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if("green".equals(apple.getColor())){
result.add(apple);
}
}

这是最常见的方法。但是这样的结构很难复用。比如我颜色不确定呢?

解决方案2:

1
2
3
4
5
6
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(apple.getColor().equals(color)){
result.add(apple);
}
}

如果我需要100g以上的且红色的苹果我就需要

1
2
3
4
5
6
7
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(apple.getColor().equals(color)
&& apple.getWeight() > weight){
result.add(apple);
}
}

如果我需要100g以上或者红色的苹果

1
2
3
4
5
6
7
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(apple.getColor().equals(color)
|| apple.getWeight() > weight){
result.add(apple);
}
}

是不是变得没完没了了?
解决方案3:

1
2
3
4
5
6
7
8
9
public static List<Apple> filterApples(List<Apple> inventory, ApplePredicate p){
List<Apple> result = new ArrayList<>();
for(Apple apple : inventory){
if(p.test(apple)){
result.add(apple);
}
}
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface ApplePredicate{
boolean test(Apple a);
}
class AppleWeightPredicate implements ApplePredicate{
public boolean test(Apple apple){
return apple.getWeight() > 150;
}
}
class AppleColorPredicate implements ApplePredicate{
public boolean test(Apple apple){
return "green".equals(apple.getColor());
}
}

class AppleRedAndHeavyPredicate implements ApplePredicate{
public boolean test(Apple apple){
return "red".equals(apple.getColor())
&& apple.getWeight() > 150;
}
}
1
List<Apple> greenApples2 = filterApples(inventory, new AppleColorPredicate());

这种方法和合适。不过如果规则也是不确定的呢?

解决方案4:

1
2
3
4
5
List<Apple> redApples2 = filterApples(inventory, new ApplePredicate() {
public boolean test(Apple a){
return a.getColor().equals("red");
}
});

Good!这样就能做到定制化了。不过通过lambda写起来更加优美

解决方案5:

1
2
List<Apple> redApples2 = filterApples(inventory, (Apple a)-> a.getColor().equals("red"));

如果我们要推广。不只是苹果而是所有的判断规则?

解决方案6:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface Predicate<T>{
boolean test(T t);
}

public static <T> List<T> filter(List<T> inventory, Predicate<T> p){
List<T> result = new ArrayList<>();
for(T apple : inventory){
if(p.test(apple)){
result.add(apple);
}
}
return result;
}

1
List<Apple> redApples2 = filter(inventory, (Apple a)-> a.getColor().equals("red"));

其实java 8 的思路也是这样的
解决方案7:

1
2
3
4
List<Apple> redApples2 = inventory
.stream()
.filter((Apple a)-> a.getColor().equals("red"))
.collect(Collectors.toList());