應用框架要求「將變化的東西與不變的東西分離」。控制框架是事件驅動系統的核心:
Controller、EventSet)內部類完美封裝「變化部分」,且能直接訪問外部類所有成員(含 private),無需傳遞上下文對象。
// Event 抽象類:時間觸發 + 動作 + 描述
abstract class Event {
long evtTime;
Event(long t) { evtTime = t; }
boolean ready() { return System.currentTimeMillis() >= evtTime; }
abstract void action();
abstract String description();
}
// Controller:事件列表 + 調度循環
class Controller {
EventSet es = new EventSet();
void addEvent(Event c) { es.add(c); }
void run() {
Event e;
while ((e = es.getNext()) != null) {
if (e.ready()) { e.action(); println(e.description()); es.removeCurrent(); }
}
}
}
public class GreenhouseControls extends Controller {
private boolean light = false, water = false;
private String thermostat = "Day";
// 內部類封裝各具體事件,直接訪問外部字段
private class LightOn extends Event { ... action() { light = true; } }
private class LightOff extends Event { ... action() { light = false; } }
private class WaterOn extends Event { ... }
private class ThermostatNight extends Event { ... }
// Bell:自重新排程事件
private class Bell extends Event {
void action() {
println("Bing!");
if (--rings > 0) addEvent(new Bell(now + 2000));
}
}
// Restart:一次性裝配全套事件循環
private class Restart extends Event {
void action() {
long tm = System.currentTimeMillis();
rings = 5;
addEvent(new ThermostatNight(tm));
addEvent(new LightOn(tm + 1000));
// ... 更多事件 ...
addEvent(new Restart(tm + 20000)); // 循環重啟
}
}
public static void main(String[] args) {
GreenhouseControls gc = new GreenhouseControls();
gc.addEvent(gc.new Restart(System.currentTimeMillis()));
gc.run();
}
}
private,實現細節對外不可見,可安全重構。light、water、thermostat、rings 直接讀寫,代碼極簡潔。Bell 同時擁有 Event 接口與 GreenhouseControls 所有成員。Bell、Restart 在 action() 中 addEvent(this) 實現循環/重啟。內部類讓控制框架「單類實現、多事件解耦」成為可能。Java 1.1 AWT 事件模型同樣依賴此機制。第 13 章將展示內部類在 GUI 編程中的更大威力。