一个MVC例子

MVC模式将代码分为三个部分:模型、视图、控制器。其中,模型定义数据以及对数据的操作接口。视图用于展示模型中的数据给用户,同时相应用户的操作,将用户的操作传递给控制器,控制器根据用户的操作执行相应的业务逻辑,访问或修改模型数据,同时控制器可以根据操作更新视图。另外,数据模型的更新可以通过观察者模式通知视图或者控制器。典型的MVC模式如下图,它们之间的交互通过方法调用或者事件模型来完成:



在Apple公司的Cocoa框架中,模型不直接与视图进行交互,它们之间的交互都通过控制器来传递,因而实现模型和控制器的解耦。此时,控制器同时监听数据模型和视图界面,根据它们的变化实现相应的逻辑控制。即:控制器可以访问和操作数据模型,模型的数据更新会通知控制器。视图的用户交互也会通知控制器,控制器可以更新视图或者响应用户操作。


下面是一个简单计算的例子,用户界面如下图:



这个简单界面实现连续乘法,在Input输入一个数,第一次输入时,点击Multiply按钮将这个数与1相乘,结果显示在Total中,第二次以后的输入,将Input中的数和Total中的数相乘。Clear按钮可以将Total恢复到初始值1.如果输入的数不是整数,弹出对话框提示用户。

在这个例子中,我们用到了上面描述的MVC之间的各种交互,先给出代码,首先是模型类:

/**
 * @author Brandon B. Lin
 * 
 */
public class CalcModel extends Observable {

	private static final String INITIAL_VALUE = "1";

	private BigInteger total;

	CalcModel() {
		reset();
	}

	public void reset() {
		total = new BigInteger(INITIAL_VALUE);
		setChanged();
		notifyObservers();
	}

	public void multiplyBy(String operand) {
		total = total.multiply(new BigInteger(operand));
		setChanged();
		notifyObservers();
	}

	public void setTotal(String newValue) {
		total = new BigInteger(newValue);
		setChanged();
		notifyObservers();
	}

	public String getTotal() {
		return total.toString();
	}
这个模型继承了抽象类Observable,如果Total的值发生变化,会通知实现注册的观察者,即下面的视图类:

/**
 * @author Brandon B. Lin
 * 
 */
class CalcView extends JFrame implements Observer {

	private static final long serialVersionUID = 5000467452832579495L;

	private static final String INITIAL_VALUE = "1";

	private JTextField userInputTextField = new JTextField(5);
	private JTextField totalTextField = new JTextField(20);
	private JButton multiplyButton = new JButton("Multiply");
	private JButton clearButton = new JButton("Clear");

	private CalcModel model;

	CalcView(CalcModel model) {
		this.model = model;
		this.model.addObserver(this);
		this.model.setTotal(INITIAL_VALUE);

		totalTextField.setText(model.getTotal());
		totalTextField.setEditable(false);

		init();

	}

	private void init() {
		JPanel content = new JPanel();
		content.setLayout(new FlowLayout());
		content.add(new JLabel("Input"));
		content.add(userInputTextField);
		content.add(multiplyButton);
		content.add(new JLabel("Total"));
		content.add(totalTextField);
		content.add(clearButton);
		this.setContentPane(content);
		this.pack();
		this.setTitle("Simple Calc - MVC");
		// The window closing event should probably be passed to the
		// Controller in a real program, but this is a short example.
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	void reset() {
		totalTextField.setText(INITIAL_VALUE);
	}

	String getUserInput() {
		return userInputTextField.getText();
	}

	void setTotal(String newTotal) {
		totalTextField.setText(newTotal);
	}

	void showError(String errMessage) {
		JOptionPane.showMessageDialog(this, errMessage);
	}

	void addMultiplyListener(ActionListener mal) {
		multiplyButton.addActionListener(mal);
	}

	void addClearListener(ActionListener cal) {
		clearButton.addActionListener(cal);
	}

	@Override
	public void update(Observable arg0, Object arg1) {
		setTotal(model.getTotal());
	}

视图类实现观察者接口Observer,初始化图像界面,响应用户操作,同时提供了注册监听器的两个接口。视图持有模型的引用,在模型变化的时候使用模型的数据来更新界面。当用户与视图交互时,作为响应,视图通知实现注册的监听器,用户操作与监听器之间的逻辑关系在控制器类中绑定。

/**
 * @author Brandon B. Lin
 * 
 */
public class CalcController {
	private CalcModel model;
	private CalcView view;

	CalcController(CalcModel model, CalcView view) {
		this.model = model;
		this.view = view;

		view.addMultiplyListener(new MultiplyListener());
		view.addClearListener(new ClearListener());
	}

	class MultiplyListener implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			String userInput = "";
			try {
				userInput = view.getUserInput();
				model.multiplyBy(userInput);

			} catch (NumberFormatException nfex) {
				view.showError("Bad input: '" + userInput + "'");
			}
		}
	}

	class ClearListener implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			model.reset();
		}
	}
}
控制器持有视图和模型的引用,在这个类中,定义了用户操作与监听器之间的逻辑关系,也就是说,对于用户的某个操作,程序该如何响应(调用哪个监听器中的方法)在这个类中定义。另外,控制器可以访问模型,更新视图或者响应用户,例如上面的方法调用:view.showError()。

下面是一个测试类,即实例化各个对象:

public class CalcMVC {
	public static void main(String[] args) {

		CalcModel model = new CalcModel();
		CalcView view = new CalcView(model);
		new CalcController(model, view);
		view.setVisible(true);
	}
}

在上面的实现中,MVC三者之间的关系较为复杂,它们之间的耦合也比较紧密。可以采用事件模型来解耦模型和视图,它们之间只通过中介控制器来通信。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值