Java 採用事件源–事件監聽者的兩級模型;C# 引入委派,形成事件源–委派–事件處理器的三級模型。這一差異直接影響了鬆耦合程度、擴充性與程式碼組織方式。
java.util.EventObject,封裝事件相關資料(如滑鼠座標)。慣例命名以 Event 結尾。java.util.EventListener,定義處理方法(如 mouseMoved(MouseEvent e))。慣例命名以 Listener 結尾。addXxxListener/removeXxxListener 註冊/註銷方法,內部維護監聽者集合,事件觸發時遍歷呼叫。// 事件物件
public class MouseMovedEvent extends EventObject {
private Point location;
public MouseMovedEvent(Component source, Point loc) { super(source); this.location = loc; }
public Point getLocation() { return location; }
}
// 監聽者介面
public interface MouseMovedListener extends EventListener {
void mouseMoved(MouseMovedEvent e);
}
// 事件源
public class EventSource {
private List listeners = new ArrayList<>();
public synchronized void addMouseMovedListener(MouseMovedListener l) { listeners.add(l); }
public synchronized void removeMouseMovedListener(MouseMovedListener l) { listeners.remove(l); }
protected void fireMouseMoved(Point p) {
MouseMovedEvent e = new MouseMovedEvent(this, p);
for (MouseMovedListener l : listeners) l.mouseMoved(e);
}
}
當監聽者介面方法過多,或需增加邏輯(如過濾、轉發)時,引入適配器類實作介面,再委派給真正處理者。多數 IDE 產生的事件代碼均採用此模式。
delegate 定義方法簽章,實例可引用符合簽章的靜態/實例方法。支援多播(+/- 操作),一個委派可串聯多個方法。
// .NET 內建委派
public delegate void EventHandler(object sender, EventArgs e);
public class Button {
public event EventHandler Click; // 事件成員
}
// 使用端
Button btn = new Button();
btn.Click += new EventHandler(OnClick); // 訂閱
btn.Click -= new EventHandler(OnClick); // 退訂
private void OnClick(object sender, EventArgs e) { /* 處理 */ }
public delegate int MyHandler(object sender, ToolBarButtonClickEventArgs e);
public event MyHandler CustomEvent;
// 訂閱
CustomEvent += new MyHandler(MyMethod);
處理器簽章完全由委派決定,不拘泥於固定的 (object, EventArgs) 形式,極大提升靈活性。
| 維度 | Java | C# |
|---|---|---|
| 模型層級 | 兩級(源–監聽者) | 三級(源–委派–處理器) |
| 介面耦合 | 強:監聽者必須實作特定介面 | 弱:僅需符合委派簽章的方法 |
| 多播支援 | 手動維護集合遍歷 | 語言原生支援(+=/-=) |
| 方法簽章靈活性 | 固定:單一 EventObject 參數 | 自由:由委派定義任意參數 |
| 適配器需求 | 常見(介面方法多、需邏輯隔離) | 較少(Lambda/匿名方法內建適配) |
| 型別安全 | 編譯期介面檢查 | 編譯期委派簽章檢查 |
C# 的委派/事件本質上是觀察者模式的語言級實現,消除了手工管理監聽者集合的樣板代碼。Java 8 引入 Lambda 與函式式介面,亦可簡化監聽者寫法,但核心模型差異依存。理解兩者本質,有助於跨平台架構設計與技術選型。