行为参数化是一种可以帮助处理频繁变更需求的软件开发模式。
例如,你为果农开发了一个苹果仓库程序。今天果农想查找仓库中的青苹果,明天他想查找重量在150克以上的苹果,后天他想查找既是青苹果重量又大于150克的苹果。
你可以写几个函数来实现这些功能,但这些函数总是要遍历苹果集合的。它们中的大部分代码都是相同的,只有一小段代码是不同的,理想上你只需要改动这一小段代码。
在Java8之前你可以使用匿名内部类+接口的方式来传递这段代码块,但这样很繁琐,而现在你可以更方便地处理这一过程。
这里有个苹果类
class Apple {
private String color;
private int weight;
public Apple(String color, int weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public int getWeight() {
return weight;
}
@Override
public String toString() {
return "Apple{" +
"color='" + color + '\'' +
", weight=" + weight +
'}';
}
}
2.1.1 初试牛刀:筛选绿苹果
最简单的解决方案
public static List<Apple> findGreen(List<Apple> apples) {
List<Apple> list = new ArrayList<>();
for (Apple apple : apples) {
if ("green".equals(apple.getColor())) {
list.add(apple);
}
}
return list;
}
那如果你要找黄色的呢,还要找绿色,蓝色,紫色的呢,你当然可以再写一些方法来解决这些问题但这并不是一个好办法。
2.1.2 再展身手:把颜色作为参数
一种简洁的做法是将颜色参数化,这样就能找到不同颜色的苹果了
public static List<Apple> findByColor(List<Apple> apples, String color) {
List<Apple> list = new ArrayList<>();
for (Apple apple : apples) {
if (color.equals(apple.getColor())) {
list.add(apple);
}
}
return list;
}
但如果现在想找到重量大于150的苹果呢
public static List<Apple> findByWeight(List<Apple> apples, int weight) {
List<Apple> list = new ArrayList<>();
for (Apple apple : apples) {
if (weight <= apple.getWeight()) {
list.add(apple);
}
}
return list;
}
这样也不错,但复制了大量代码来实现遍历库存,并对苹果应用筛选条件。
这打破了DRY(Don't Repeat Yourself, 不要重复自己)
的软件工程原则,此时如果你想更改遍历方式来提升程序的性能,那么你需要更改大量的代码,这非常麻烦。
2.1.3 第三次尝试:为你能想到的每个属性做筛选
你现在要找到绿苹果并且重量大于150
下面给出两种笨拙的方法
List<Apple> target = findByColor(apples, "green");
target = findByWeight(target, 150);
可以将之前的两个方法利用起来,但这样会两次遍历集合,性能不好。
public static List<Apple> findByWeightAndColor(List<Apple> apples, String color, int weight) {
List<Apple> list = new ArrayList<>();
for (Apple apple : apples) {
if (weight <= apple.getWeight() && color.equals(apple.getColor())) {
list.add(apple);
}
}
return list;
}
这样看上去也还行,但如果筛选的条件变多,岂不是要写很多个这样的方法,这令人心碎。
现在你需要一种更好的方式来将苹果的筛选标准告诉findXXX
方法,不要着急在下一节将会介绍行为参数化来实现这种灵活性。
下面是完整的代码
package lambdasinaction.chap1;
import java.util.ArrayList;
import java.util.List;
class Apple {
private String color;
private int weight;
public Apple(String color, int weight) {
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public int getWeight() {
return weight;
}
@Override
public String toString() {
return "Apple{" +
"color='" + color + '\'' +
", weight=" + weight +
'}';
}
}
public class Test06 {
public static List<Apple> findGreen(List<Apple> apples) {
List<Apple> list = new ArrayList<>();
for (Apple apple : apples) {
if ("green".equals(apple.getColor())) {
list.add(apple);
}
}
return list;
}
public static List<Apple> findByColor(List<Apple> apples, String color) {
List<Apple> list = new ArrayList<>();
for (Apple apple : apples) {
if (color.equals(apple.getColor())) {
list.add(apple);
}
}
return list;
}
public static List<Apple> findByWeight(List<Apple> apples, int weight) {
List<Apple> list = new ArrayList<>();
for (Apple apple : apples) {
if (weight <= apple.getWeight()) {
list.add(apple);
}
}
return list;
}
public static List<Apple> findByWeightAndColor(List<Apple> apples, String color, int weight) {
List<Apple> list = new ArrayList<>();
for (Apple apple : apples) {
if (weight <= apple.getWeight() && color.equals(apple.getColor())) {
list.add(apple);
}
}
return list;
}
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
apples.add(new Apple("red", 100));
apples.add(new Apple("yellow", 200));
apples.add(new Apple("green", 100));
apples.add(new Apple("green", 200));
List<Apple> green = findGreen(apples);
System.out.println("=================================");
System.out.println(green);
System.out.println("=================================");
List<Apple> target = findByColor(apples, "green");
target = findByWeight(target, 150);
System.out.println(target);
System.out.println("=================================");
target = findByWeightAndColor(apples, "green", 150);
System.out.println(target);
}
}
程序的输出结果 :
=================================
[Apple{color='green', weight=100}, Apple{color='green', weight=200}]
=================================
[Apple{color='green', weight=200}]
=================================
[Apple{color='green', weight=200}]