需求:主視窗 (庫存查詢) 開啟子視窗 (高級查詢),子視窗組合 SQL 條件後傳回主視窗,主視窗據此刷新 `JTable`。本文提供三種耦合度遞減的實現模式。
public class MainFrame extends JFrame {
private JTable table;
private DefaultTableModel model;
public void openAdvancedQuery() {
AdvancedQueryDialog dialog = new AdvancedQueryDialog(this); // 傳 this
dialog.setVisible(true);
}
// 供子視窗呼叫
public void refreshTable(String sql) {
// 執行查詢、更新 model
model.setRowCount(0);
// ... 查詢資料庫填充 model ...
}
}
public class AdvancedQueryDialog extends JDialog {
private MainFrame parent;
public AdvancedQueryDialog(MainFrame parent) {
this.parent = parent;
// 確定按鈕事件
btnOk.addActionListener(e -> {
String sql = buildSql();
parent.refreshTable(sql); // 直接呼叫父視窗方法
dispose();
});
}
}
// 共享介面
public interface QueryListener {
void onQueryBuilt(String sql);
}
// 控制器持有兩個視圖引用
public class AppController {
private MainFrame mainFrame;
private AdvancedQueryDialog queryDialog;
public AppController() {
mainFrame = new MainFrame(this);
queryDialog = new AdvancedQueryDialog(this);
}
// 主視窗呼叫
public void showAdvancedQuery() { queryDialog.setVisible(true); }
// 子視窗呼叫(實作 QueryListener)
public void onQueryBuilt(String sql) {
mainFrame.refreshTable(sql);
queryDialog.dispose();
}
}
// 主視窗
public class MainFrame extends JFrame {
private AppController controller;
public MainFrame(AppController controller) { this.controller = controller; }
// 開啟查詢按鈕
btnAdvanced.addActionListener(e -> controller.showAdvancedQuery());
public void refreshTable(String sql) { /* ... */ }
}
// 子視窗
public class AdvancedQueryDialog extends JDialog {
private AppController controller;
public AdvancedQueryDialog(AppController controller) { this.controller = controller; }
btnOk.addActionListener(e -> controller.onQueryBuilt(buildSql()));
}
// 事件類別
public class QueryBuiltEvent {
public final String sql;
public QueryBuiltEvent(String sql) { this.sql = sql; }
}
// 使用 Guava EventBus / Spring ApplicationEvent / 自訂簡易總線
public class EventBus {
private static final List> subscribers = new CopyOnWriteArrayList<>();
public static void subscribe(Consumer
| 模式 | 耦合度 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|---|
| 直接引用 | 高 | 代碼最少、直觀 | 難測試、難復用、循環依賴風險 | 小工具、原型、兩視窗固定綁定 |
| 中央控制器 | 中 | 符合 MVC、易單元測試、邏輯集中 | 控制器類別可能膨脹 | 標準桌面應用、中型專案 |
| 事件總線 | 低 | 完全解耦、支援多訂閱者、易擴展 | 流程隱式、除錯稍難 | 大型模組化專案、插件架構 |
根據專案規模選擇:小專案用「直接引用」,中型用「中央控制器」,大型模組化用「事件總線」。核心都是**主視窗暴露 `refreshTable(sql)` 方法,子視窗構建 SQL 後回呼**。