通过行为参数化传递代码
行为参数化就是可以帮助你处理频繁变更的需求的一种软件开发模式。
2.1 应对不断变化的需求
编写能够应对变化的需求的代码并不容易。
2.1.1 初试牛刀:筛选绿苹果
2.1.2 再展身手: 把颜色作为参数
2.1.3 第三次尝试: 对你能想到的每个属性做筛选
通过上面的三个案例,逐次来明白使用行为参数化来应对不断变化的需求的优势。
2.2 行为参数化
定义一族算法,封装起来,然后再运行时选择一个算法
public interface AppleFormatter{
String accept(Apple a);
}
public class AppleFancyFormatter implements AppleFormatter{
public String accept(Apple a) {
String characteristic = apple.getWeight() > 150 ? "heavy" : "light";
return "A " + characteristic + " " + apple.getColor() + " apple";
}
}
public class AppleSimpleFormatter implements AppleFormatter{
public String accept(Apple a) {
return "An apple of " + apple.getWeight() + "g" ;
}
}
public static void prettyPrintApple(List<Apple> inventory, AppleFormatter formatter) {
for(Apple apple : inventory){
String output = formatter.accept(apple);
System.out.println(output);
}
}
2.3 对付啰嗦
Java有一个机制称为匿名类,可以同时声明和实例化一个类。
2.3.1 匿名类
匿名类没有名字,允许同时声明并实例化一个类
2.3.2 第五次尝试:使用匿名类
List<Apple> redApples = prettyPrintApple(inventory, new AppleFormatter() {
public boolean test(Apple apple) {
return "An apple of " + apple.getWeight() + "g" ;
}
});
但是匿名类第一往往很笨重,第二会让人觉得很费解,所以还是更加提倡行为参数化。
2.3.3 第六次尝试:使用Lambda表达式
List<Apple> result = prettyPrintApple(inventory, (Apple, apple) -> "An apple of " + apple.getWeight() + "g")
2.3.4 第七次尝试:将List类型抽象化
public interface Predicate<T> {
boolean test(T t);
}
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> result = new ArrayList<>();
for(T e: list){
if (p.test(e)) {
result.add(e);
}
}
return result;
}
2.4 真实的例子
Java API中的很多方法都可以用不同的行为来参数化。
2.4.1 用Comparator来排序
public interface Comparator<T> {
public int compare(T o1, T o2);
}
inventory.sort(new Comparator<Apple>() {
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
}
}
inventory.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
2.4.2 用Runnable执行代码块
线程就像是轻量级的进程,它们自己执行一个代码块。
public interface Runnable {
public void run();
}
Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("Hello world");
}
});
Thread t = new Thread(() -> System.out.println("Hello world"));
2.4.3 GUI事件处理
2.5小结
以下是你应从本章中学到的关键概念。
行为参数化,就是一个方法接受多个不同的行为作为参数,并在内部使用它们,完成不同行为的能力。
行为参数化可让代码更好地适应不断变化的要求,减轻未来的工作量。
传递代码,就是将新行为作为参数传递给方法。但在Java 8之前这实现起来很啰嗦。为接口声明许多只用一次的实体类而造成的啰嗦代码,在Java 8之前可以用匿名类来减少。
Java API包含很多可以用不同行为进行参数化的方法,包括排序、线程和GUI处理。