MVC Design Pattern

Model

    模型代表核心业务数据,和核心的业务功能,因此,Model应该被设计成独立于特定的输入行为和输出表示的程序。

View

    视图模块将模型的中的数据显示给用户。而因为相同的数据可以有不同形式的显示方法,所以一个模型可以有很多个视图view。

Controller
    每个view可以拥有与之相关联的controller组件。Controllers负责处理用户输入,通常是从鼠标运动,按钮,和键盘事件引起的输入。然后负责调用模型的相应功能。


数据更新:改变-传播机制(change-propagation)

  • 如果用户通过一个view的controller改变了model,所有的其它的view必须反映出该改变。
  • 当数据发生变化的时候,model通知所有的view,告诉他们数据已经改变了;
  • Views可以遍历model中的数据,以便发现到底是什么改变了。然后更新显示数据。
  • 改变-传播机制(change-propagation)机制保证了用户界面和模型的一致性。这个改变-传播机制可以由观察着模式的Publisher-Subscriber方式实现。


MVC的优点

1) 容易增加或者改变视图

  • 事务逻辑被封装在Model中,所以在新增加一个视图的时候,不必要改动模型,而是因为事务逻辑都是一样的,所以只需要新增加一个视图类即可。

2)容易独立地更新每个独立的软件模块

  • 由于一个应用被分离为三个软件模块,因此,我们可以独立地改变其中的一个模块,而不影响其它两个模块。例如,一个应用的业务流程或者业务规则的改变只需改动MVC的模型层。

3)有利于软件的工程化管理

  • 由于不同的层各司其职,每一层不同的应用具有某些相同的特征,有利于通过工程化、工具化产生管理程序代码。例如,使用工具生成图形界面(View)

Design Examples Using the MVC Design Pattern




设计方案3工作原理

  • 用户输入. 用户通过使用 CarAuctionGUI 中的Cars列表选择待卖的车,点击Search,以便获取车的图片;然后输入拍价,点击Bit,给出价格。
  • 捕捉用户输入. 每次点击按钮产生的事件,都被Controller对象捕捉,然后调用 actionPerformed() 方法。
  • 更新模型数据. 在actionPerformed()方法中,将根据事件的类型,分别使用setSelectedCar 或者setBitPrice 方法更新CarModel的数据
  • Model通知View. 由于CarGUIView、CarBitView与CarModel之间存在观察者/被观察者的关系,所以当CarModel的状态改变了的时候,CarGUIView和CarBitView的update()方法将被自动调用。
  • 更新View. 在update()方法中,调用CarModel的getSelectedCar 或者getBitPrice 方法得到最新的数据,然后根据数据,更新视图。
设计要点
  • CarModel实现了interface Observable,实现了方法notifyObservers()和register(Observerobs)。
  • CarGUIInfoView和CarBitInfoView实现了interfaceObserver, 实现了方法update()。
  • 每个CarGUIInfoView和CarBitInfoView都将自己注册为CarModel的观察者。每当CarModel的状态改变的时候,其方法notifyObservers将改变告诉给它所有的观察者,观察者的update()可以自动查询CarModel,了解到底是什么状态改变了,从而作出响应的反应。
  • 事实上,notifyObservers()的代码中,直接调用了观察者中的update()方法。以下是代码。
public class CarAuctionGUI extends JFrame {
	static public void main(String argv[]) {
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				cm = new CarModel();
				cgiv = new CarGUIInfoView(cm);
				cbiv = new CarBitInfoView(cm);
				cm.register(cgiv); // 将视图对象注册到模型
				cm.register(cbiv); // 将视图对象注册到模型

				CarAuctionGUI frame = new CarAuctionGUI();
			}
		});
	}
}

public class Controller implements ActionListener {
	private CarAuctionGUI objCarGUI;
	private CarModel cm;
	private String carPrice;

	public void actionPerformed(ActionEvent e) {
		String searchResult = null;
		if (e.getActionCommand().equals(SEARCH)) {
			String selectedCar = objCarGUI.getSelectedCar();
			cm.setSelectedCar(selectedCar); // 更新模型数据
			cm.setCarFileUrl();
			cm.setupImageIcon();
			cm.setSearchBtnClickInfo(true);
			cm.notifyObservers(); // 通知观察者
			cm.setSearchBtnClickInfo(false);
		}
		if (e.getActionCommand().equals(CarAuctionGUI.BIT)) {
			carPrice = objCarGUI.getBitPrice();
			cm.setBitPrice(carPrice); // 更新模型数据
			cm.setBitBtnClickInfo(true);
			cm.notifyObservers(); // 通知观察者
			cm.setBitBtnClickInfo(false);
		}
	}
}
public class CarModel implements Observable {
	private ArrayList<Observer> observersList;
	private ImageIcon imgIcon;
	private URL url;
	private String[] carNameList;
	private String carSelected;
	private String bitPrice;
	private boolean isBitBtnClicked = false;
	private boolean isSearchBtnClicked = false;
	static final String CARFILES = "CarFiles/";
	static final String CARIMAGES = "CarImages/";

	public CarModel() {
		observersList = new ArrayList<Observer>();
		carNameList = new String[200];
	}

	public void setCarList(String[] cars) {
		carNameList = cars;
	}

	public String[] getCarList() {
		return carNameList;
	}

	public void setSelectedCar(String sCar) {
		carSelected = sCar;
	}

	public String getSelectedCar() {
		return carSelected;
	}

	public void setBitPrice(String bPrice) {
		bitPrice = "";
		bitPrice = bitPrice + bPrice;
	}

	public String getBitPrice() {
		return bitPrice;
	}

	public void setCarFileUrl() {
		String fileURLStr = CARFILES + carSelected + ".html";
		File file = new File(fileURLStr);
		URI uri = file.toURI();
		url = uri.toURL();
	}

	public URL getCarFileURL() {
		return url;
	}

	public void setupImageIcon() {
		String iconStr = CARIMAGES + carSelected + ".jpg";
		imgIcon = createImageIcon(iconStr);
	}

	public ImageIcon getImageIcon() {
		return imgIcon;
	}

	public void setBitBtnClickInfo(boolean opt) {
		isBitBtnClicked = opt;
	}

	public boolean isBitBtnClicked() {
		return isBitBtnClicked;
	}

	public void setSearchBtnClickInfo(boolean opt) {
		isSearchBtnClicked = opt;
	}

	public boolean isSearchBtnClicked() {
		return isSearchBtnClicked;
	}

	public void register(Observer obs) {
		observersList.add(obs);
	}

	public void notifyObservers() {
		for (int i = 0; i < observersList.size(); i++) {
			Observer observer = (Observer) observersList.get(i);
			observer.update(this);
		}
	}

	protected ImageIcon createImageIcon(String path) {
		URL imgURL = getClass().getResource(path);
		if (imgURL != null) {
			return new ImageIcon(imgURL);
		} else {
			return null;
		}
	}
} // End of class
class CarBitInfoView extends JFrame implements Observer {
	private JLabel bitLabel;
	private JTextArea bitText;
	private CarModel model;
	private JScrollPane textPane;

	public CarBitInfoView(CarModel cmodel) {
		model = cmodel;

		bitLabel = new JLabel("Bits offered:");
		bitText = new JTextArea(4, 20);
		bitText.setFont(new Font("Serif", Font.PLAIN, 14));

		JScrollPane textPane = new JScrollPane(bitText);
		Container contentPane = getContentPane();
		contentPane.add(bitLabel, BorderLayout.NORTH);
		contentPane.add(textPane, BorderLayout.CENTER);
		setVisible(true);
	}

	// CarBitInfoView代码续
	public void update(Observable subject) {
		if ((subject == model) && (model.isBitBtnClicked())) {
			// 从model获得数据
			String sCar = model.getSelectedCar();
			String pr = model.getBitPrice();
			// 显示在视图上
			bitText.append("\n Bit price for " + sCar + "=" + pr);
		}
	}
}// end CarBitInfoView



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值