| 層 | 職責 | 示例類 |
|---|---|---|
| Model | 數據狀態、業務邏輯、持久化 | ContactModel |
| View | UI 組件佈局、數據顯示、用戶輸入收集 | ContactEditView, ContactDisplayView |
| Controller | 事件處理、模型更新、視圖同步 | ContactEditController |
// 模型接口
interface ContactModel {
void setName(String name);
String getName();
void setPhone(String phone);
String getPhone();
void setEmail(String email);
String getEmail();
void addChangeListener(ChangeListener l);
void removeChangeListener(ChangeListener l);
}
// 視圖接口
interface ContactView {
void setModel(ContactModel model);
void setController(ContactController controller);
void refresh(); // 從模型同步數據
}
// 控制器接口
interface ContactController {
void handleNameChange(String newName);
void handlePhoneChange(String newPhone);
void handleEmailChange(String newEmail);
}
class ContactModelImpl implements ContactModel {
private String name, phone, email;
private final EventListenerList listeners = new EventListenerList();
// 屬性讀寫 + 觸發事件
public void setName(String name) {
if (!Objects.equals(this.name, name)) {
this.name = name;
fireChangeEvent();
}
}
public String getName() { return name; }
// phone, email 同理...
// 監聽器管理
public void addChangeListener(ChangeListener l) {
listeners.add(ChangeListener.class, l);
}
public void removeChangeListener(ChangeListener l) {
listeners.remove(ChangeListener.class, l);
}
private void fireChangeEvent() {
ChangeEvent e = new ChangeEvent(this);
for (ChangeListener l : listeners.getListeners(ChangeListener.class)) {
l.stateChanged(e);
}
}
}
class ContactEditView extends JPanel implements ContactView {
private JTextField nameField, phoneField, emailField;
private ContactModel model;
private ContactController controller;
public ContactEditView() {
setLayout(new GridLayout(3, 2));
add(new JLabel("姓名:")); add(nameField = new JTextField());
add(new JLabel("電話:")); add(phoneField = new JTextField());
add(new JLabel("郵箱:")); add(emailField = new JTextField());
// 綁定輸入事件 → 控制器
nameField.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) { notifyChange(); }
public void removeUpdate(DocumentEvent e) { notifyChange(); }
public void changedUpdate(DocumentEvent e) { notifyChange(); }
void notifyChange() {
if (controller != null) controller.handleNameChange(nameField.getText());
}
});
// phoneField, emailField 同理...
}
public void setModel(ContactModel model) {
this.model = model;
model.addChangeListener(e -> refresh());
}
public void setController(ContactController controller) {
this.controller = controller;
}
public void refresh() {
nameField.setText(model.getName());
phoneField.setText(model.getPhone());
emailField.setText(model.getEmail());
}
}
class ContactDisplayView extends JPanel implements ContactView {
private JLabel nameLabel, phoneLabel, emailLabel;
private ContactModel model;
public ContactDisplayView() {
setLayout(new GridLayout(3, 2));
add(new JLabel("姓名:")); add(nameLabel = new JLabel());
add(new JLabel("電話:")); add(phoneLabel = new JLabel());
add(new JLabel("郵箱:")); add(emailLabel = new JLabel());
}
public void setModel(ContactModel model) {
this.model = model;
model.addChangeListener(e -> refresh());
}
public void setController(ContactController c) {} // 無需控制器
public void refresh() {
nameLabel.setText(model.getName());
phoneLabel.setText(model.getPhone());
emailLabel.setText(model.getEmail());
}
}
class ContactEditController implements ContactController {
private ContactModel model;
public ContactEditController(ContactModel model) {
this.model = model;
}
public void handleNameChange(String name) {
model.setName(name); // 觸發事件 → 所有視圖自動 refresh()
}
public void handlePhoneChange(String phone) {
model.setPhone(phone);
}
public void handleEmailChange(String email) {
model.setEmail(email);
}
}
public class RunMVCPattern {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
// 1. 創建共享模型
ContactModel model = new ContactModelImpl();
// 2. 創建視圖
ContactView editView = new ContactEditView();
ContactView displayView = new ContactDisplayView();
// 3. 創建控制器
ContactController controller = new ContactEditController(model);
// 4. 綁定關係
editView.setModel(model);
editView.setController(controller);
displayView.setModel(model); // 共享同一模型
// 5. 構建窗口
JFrame editFrame = new JFrame("聯繫人編輯");
editFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
editFrame.add(editView);
editFrame.pack();
editFrame.setLocation(100, 100);
editFrame.setVisible(true);
JFrame displayFrame = new JFrame("聯繫人顯示(同步更新)");
displayFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
displayFrame.add(displayView);
displayFrame.pack();
displayFrame.setLocation(500, 100);
displayFrame.setVisible(true);
});
}
}
PropertyChangeSupport 替換手動監聽器SwingWorker 處理異步數據加載JavaFX + MVVM (FXML + ViewModel) 替代 Swing MVC這個示例展示了 MVC 在桌面應用中的經典應用:模型發射事件,視圖訂閱事件,控制器轉發命令,實現了關注點清晰分離。