正如您所发现的,“模型-视图-控制器”模式不是万能药,但它提供了一些优势。在MVC中扎根,Swing可分离模型体系结构在“ Swing体系结构概述”中进行了讨论。基于此轮廓,下面的示例显示了一个更简单的游戏的MVC实现,它说明了相似的原理。请注意,Model管理一个Piece,随机选择。响应用户的选择,View调用check()方法,同时侦听来自Modelvia的响应update()。在View随后利用所获得的信息来更新自身Model。类似地,Controller可以reset()在Model。特别是中没有绘图,而中Model也没有游戏逻辑View。这个稍微复杂一些的游戏旨在说明相同的概念。
附录:我已经修改了原始示例,以显示MVC如何在View不更改的性质的情况下增强Model。
附录:正如@akf所观察到的那样,MVC取决于观察者模式。您Model需要一种方法来通知View更改。几种方法被广泛使用:
在下面的示例中,为简单起见对其进行了Model扩展Observable。
如应用程序中EventListenerList所示,更常见的方法是使用,Converter并由大量EventListener子接口和实现类建议。
第三种选择是使用a PropertyChangeListener,如此处和此处所示。
附录:有关Swing控制器的一些常见问题已在此处和此处解决。
import java.awt.BorderLayout;import java.awt.Color;import java.awt.Component;import java.awt.EventQueue;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.RenderingHints;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.util.Observable;import java.util.Observer;import java.util.Random;import javax.swing.Icon;import javax.swing.JButton;import javax.swing.Jframe;import javax.swing.JLabel;import javax.swing.JPanel;public class MVCGame implements Runnable { public static void main(String[] args) { EventQueue.invokeLater(new MVCGame()); } @Override public void run() { Jframe f = new Jframe(); f.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE); f.add(new MainPanel()); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); }}class MainPanel extends JPanel { public MainPanel() { super(new BorderLayout()); Model model = new Model(); View view = new View(model); Control control = new Control(model, view); JLabel label = new JLabel("Guess what color!", JLabel.CENTER); this.add(label, BorderLayout.NORTH); this.add(view, BorderLayout.CENTER); this.add(control, BorderLayout.SOUTH); }}class Control extends JPanel { private Model model; private View view; private JButton reset = new JButton("Reset"); public Control(Model model, View view) { this.model = model; this.view = view; this.add(reset); reset.addActionListener(new ButtonHandler()); } private class ButtonHandler implements ActionListener { @Override public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); if ("Reset".equals(cmd)) { model.reset(); } } }}class View extends JPanel { private static final String s = "Click a button."; private Model model; private ColorIcon icon = new ColorIcon(80, Color.gray); private JLabel label = new JLabel(s, icon, JLabel.CENTER); public View(Model model) { super(new BorderLayout()); this.model = model; label.setVerticalTextPosition(JLabel.BOTTOM); label.setHorizontalTextPosition(JLabel.CENTER); this.add(label, BorderLayout.CENTER); this.add(genButtonPanel(), BorderLayout.SOUTH); model.addObserver(new ModelObserver()); } private JPanel genButtonPanel() { JPanel panel = new JPanel(); for (Piece p : Piece.values()) { PieceButton pb = new PieceButton(p); pb.addActionListener(new ButtonHandler()); panel.add(pb); } return panel; } private class ModelObserver implements Observer { @Override public void update(Observable o, Object arg) { if (arg == null) { label.setText(s); icon.color = Color.gray; } else { if ((Boolean) arg) { label.setText("Win!"); } else { label.setText("Keep trying."); } } } } private class ButtonHandler implements ActionListener { @Override public void actionPerformed(ActionEvent e) { PieceButton pb = (PieceButton) e.getSource(); icon.color = pb.piece.color; label.repaint(); model.check(pb.piece); } } private static class PieceButton extends JButton { Piece piece; public PieceButton(Piece piece) { this.piece = piece; this.setIcon(new ColorIcon(16, piece.color)); } } private static class ColorIcon implements Icon { private int size; private Color color; public ColorIcon(int size, Color color) { this.size = size; this.color = color; } @Override public void paintIcon(Component c, Graphics g, int x, int y) { Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setColor(color); g2d.fillOval(x, y, size, size); } @Override public int getIconWidth() { return size; } @Override public int getIconHeight() { return size; } }}class Model extends Observable { private static final Random rnd = new Random(); private static final Piece[] pieces = Piece.values(); private Piece hidden = init(); private Piece init() { return pieces[rnd.nextInt(pieces.length)]; } public void reset() { hidden = init(); setChanged(); notifyObservers(); } public void check(Piece guess) { setChanged(); notifyObservers(guess.equals(hidden)); }}enum Piece { Red(Color.red), Green(Color.green), Blue(Color.blue); public Color color; private Piece(Color color) { this.color = color; }}


