行为参数化是一个很有用的模式,它能够轻松地适应不断变化的需求。这 种模式可以把一个行为(一段代码)封装起来,并通过传递和使用创建的行为(例如对Apple的 不同谓词)将方法的行为参数化。前面提到过,这种做法类似于策略设计模式。你可能已经在实 践中用过这个模式了。Java API中的很多方法都可以用不同的行为来参数化。这些方法往往与匿 名类一起使用。我们会展示三个例子,这应该能帮助你巩固传递代码的思想了:用一个 Comparator排序,用Runnable执行一个代码块,以及GUI事件处理。
用 Comparator 来排序
对集合进行排序是一个常见的编程任务。比如,你的那位农民朋友想要根据苹果的重量对库 存进行排序,或者他可能改了主意,希望你根据颜色对苹果进行排序。听起来有点儿耳熟?是的, 你需要一种方法来表示和使用不同的排序行为,来轻松地适应变化的需求。
在Java 8中,List自带了一个sort方法(你也可以使用Collections.sort)。sort的行为 可以用java.util.Comparator对象来参数化,它的接口如下:
// java.util.Comparator
public interface Comparator<T> {
public int compare(T o1, T o2);
}
因此,你可以随时创建Comparator的实现,用sort方法表现出不同的行为。比如,你可以 使用匿名类,按照重量升序对库存排序:
inventory.sort(new Comparator<Apple>() {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
});
如果农民改了主意,你可以随时创建一个Comparator来满足他的新要求,并把它传递给 sort方法。而如何进行排序这一内部细节都被抽象掉了。用Lambda表达式的话,看起来就是 这样:
inventory.sort(
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
用 Runnable 执行代码块
线程就像是轻量级的进程:它们自己执行一个代码块。但是,怎么才能告诉线程要执行哪块 代码呢?多个线程可能会运行不同的代码。我们需要一种方式来代表稍候执行的一段代码。在 Java里,你可以使用Runnable接口表示一个要执行的代码块。请注意,代码不会返回任何结果 (即void):
// java.lang.Runnable
public interface Runnable{
public void run();
}
你可以像下面这样,使用这个接口创建执行不同行为的线程:
Thread t = new Thread(new Runnable() {
public void run(){
System.out.println("Hello world");
}
});
用Lambda表达式的话,看起来是这样:
Thread t = new Thread(() -> System.out.println("Hello world"));
GUI 事件处理
GUI编程的一个典型模式就是执行一个操作来响应特定事件,如鼠标单击或在文字上悬停。
例如,如果用户单击“发送”按钮,你可能想显示一个弹出式窗口,或把行为记录在一个文件中。 你还是需要一种方法来应对变化;你应该能够作出任意形式的响应。在JavaFX中,你可以使用 EventHandler,把它传给setOnAction来表示对事件的响应:
Button button = new Button("Send");
button.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
label.setText("Sent!!");
}
});
这里,setOnAction方法的行为就用EventHandler参数化了。用Lambda表达式的话,看 起来就是这样:
button.setOnAction((ActionEvent event) -> label.setText("Sent!!"));
行为参数化,就是一个方法接受多个不同的行为作为参数,并在内部使用它们,完成不 同行为的能力。
行为参数化可让代码更好地适应不断变化的要求,减轻未来的工作量。
传递代码,就是将新行为作为参数传递给方法。但在Java 8之前这实现起来很啰嗦。为接 口声明许多只用一次的实体类而造成的啰嗦代码,在Java 8之前可以用匿名类来减少。
Java API包含很多可以用不同行为进行参数化的方法,包括排序、线程和GUI处理。