初學者常將所有監聽邏輯塞入主 JFrame/JPanel:actionPerformed 中大量 if (e.getSource() == btnX) 判斷,導致類職責不清、難擴展、難測試。本文以「游泳隊員性別篩選」為例,逐步重構為高內聚低耦合的架構。
public class Swimmer {
private String name; private int age; private String club; private boolean female;
// 構造器、getter、isFemale()...
}
public class Swimmers { // 集合類
private Vector<Swimmer> kids = new Vector<>();
public Vector<Swimmer> getList(boolean female) { /* 篩選邏輯 */ }
public Vector<Swimmer> getList() { /* 全部 */ }
}
public interface Command { void execute(); }
public abstract class SexButton extends JRadioButton implements Command {
protected Swimmers swimmers; protected Mediator mediator; // 階段2引入
public SexButton(String title, Swimmers s, Mediator m, ActionListener al) {
super(title); this.swimmers=s; this.mediator=m; addActionListener(al);
}
public abstract void execute();
}
public class FemaleButton extends SexButton {
public void execute() { mediator.loadList(swimmers.getList(true)); }
}
// MaleButton, BothButton 同理
主類監聽器極簡:
public void actionPerformed(ActionEvent e) {
((Command) e.getSource()).execute(); // 多態分發,無 if-else
}
按鈕不再直接持有 JList 引用,改為依賴 Mediator:
public class Mediator {
private JawList kidList; // 封裝 JList 的視圖組件
public void loadList(Vector<Swimmer> v) {
kidList.clear();
for (Swimmer s : v) kidList.add(s.getName());
}
}
按鈕僅調用 mediator.loadList(...),視圖變更 (如換成表格) 僅修改 Mediator。
SexButton 構造器封裝公共初始化 (添加監聽器、保存依賴),子類只實現 execute(),符合「好萊塢原則」。
public class JListData extends AbstractListModel {
private Vector<String> data = new Vector<>();
public void addElement(String s) { data.add(s); fireIntervalAdded(this, data.size()-1, data.size()); }
public void clear() { int sz=data.size(); data.clear(); fireIntervalRemoved(this,0,sz); }
// getSize, getElementAt...
}
public class JawList extends JScrollPane {
private JListData listContents = new JListData();
private JList list = new JList(listContents);
// add/remove/clear 代理到 listContents
}
優勢:數據變更自動通知視圖,按鈕/中介者僅操作 JListData,完全不感知 JList 存在。
| 模式 | 解決問題 | 關鍵角色 | 適用場景 |
|---|---|---|---|
| 命令 | 消除巨大的 actionPerformed 分發 | Command 接口、具體命令類 | 菜單項、工具欄、按鈕動作 |
| 中介者 | 解耦多個交互組件 (按鈕、列表、表單) | Mediator、Colleague | 複雜對話框、向導、多視圖聯動 |
| 模板方法 | 固定算法骨架,延遲具體步驟到子類 | 抽象基類、鉤子方法 | 框架擴展點、向導步驟 |
| 觀察者 | 數據模型與視圖分離,自動同步 | Subject/Observable、Observer | MVC/MVP、綁定框架基礎 |
if-else 地獄。AbstractListModel/TableModel**:免費獲得觀察者機制,Swing 設計初衷。設計模式非理論裝飾,而是解決具體耦合痛點的工具。通過命令+中介者+觀察者組合,將百行臃腫主類拆分為單一職責的類群,實現「開閉原則」:新增篩選條件只需添加新 Button 類,零修改現有代碼。