这学期有一门软件体系结构的实验课,刚过去的一个星期做了一个关于MVC框架的实验
实验也简单,就是在原有的JAVA程序代码基础上改动一下,在视图中加一些功能。虽简单
但是其中的MVC思想还是很典型的。
一.MVC简介
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用于组织代码用一种业务逻辑和数据显示分离的方法,这个方法的假设前提是如果业务逻辑被聚集到一个部件里面,而且界面和用户围绕数据的交互能被改进和个性化定制而不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。MVC开始是存在于桌面程序中的,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的
是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据可以分别用柱状图、饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。模型-视图-控制器(MVC)是Xerox PARC在二十世纪八十年代为编程语言Smalltalk-80发明的一种软件设计模式,已被广泛使用。后来被推荐为Oracle旗下Sun公司Java EE平台的设计模式,并且受到越来越多的使用ColdFusion和PHP的开发者的欢迎。模型-视图-控制器模式是一个有用的工具箱,它有很多好处,但也有一些缺点。
二.MVC是框架模式并不是设计模式
有很多程序员往往把框架模式和设计模式混淆,认为MVC是一种设计模式。实际上它们完全是不同的概念。框架、设计模式这两个概念总容易被混淆,其实它们之间还是有区别的。框架通常是代码重用,而设计模式是设计重用,架构则介于两者之间,部分代码重用,部分设计重用,有时分析也可重用。在软件生产中有三种级别的重用:内部重用,即在同一应用中能公共使用的抽象块;代码重用,即将通用模块组合成库或工具集,
以便在多个应用和领域都能使用;应用框架的重用,即为专用领域提供通用的或现成的基础结构,以获得最高级别的重用性。框架与设计模式虽然相似,但却有着根本的不同。设计模式是对在某种环境中反复出现的问题以及解决该问题的方案的描述,它比框架更抽象;框架可以用代码表示,也能直接执行或复用,而对模式而言只有实例才能用
代码表示;设计模式是比框架更小的元素,一个框架中往往含有一个或多个设计模式,框架总是针对某一特定应用领域,但同一模式却可适用于各种应用。可以说,框架是软件,而设计模式是软件的知识。
框架模式有哪些?
MVC、MTV、MVP、CBD、ORM等等;
框架有哪些?
C++语言的QT、MFC、gtk,Java语言的SSH 、SSI,php语言的 smarty(MVC模式),python语言的django(MTV模式)等等
设计模式有哪些?
工厂模式、适配器模式、策略模式等等
简而言之:设计模式是大智慧,用来对软件设计进行分工;框架模式是小技巧,对具体问题提出解决方案,以提高
代码复用率,降低耦合度。
三.例子(就是我的实验)
1.首先是包中的主程序,位于com下,全路径com.MainFrame.java
/* * MainFrame.java */ package com; import com.controller.Controller; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.LayoutManager; import java.awt.event.*; import javax.swing.*; import com.view.*; import com.model.CircleModel; public class MainFrame extends JFrame{ public CircleModel model; public ViewPanel vp; public RTextField rTextField; public CTextField cTextField; public STextField sTextField; public ControlSlider slider; public BTextField bTextField; public DTextField dTextField;////// private JPanel topPanel = new JPanel(); private JPanel bottomPanel = new JPanel(); public JButton jButton1 = new JButton("更新"); private JLabel jLabel1 = new JLabel("半径"); private JLabel jLabel2 = new JLabel("周长"); private JLabel jLabel3 = new JLabel("面积"); private JLabel jLabel4 = new JLabel("球面积"); //private JLabel jLabel5 = new JLabel("直径"); /** Creates a new instance of MainFrame */ public MainFrame(String title) { super.setTitle(title); initComponent(); new Controller(this); } private void initComponent(){ model=new CircleModel(10.0); vp = new ViewPanel(model); rTextField = new RTextField(model); cTextField = new CTextField(model); sTextField = new STextField(model); bTextField = new BTextField(model); //dTextField = new DTextField(model);////// slider = new ControlSlider(model); cTextField.setEditable(false); sTextField.setEditable(false); bTextField.setEditable(false); // dTextField.setEditable(false);////// topPanel.setLayout(new FlowLayout()); topPanel.add(jLabel1); topPanel.add(rTextField); topPanel.add(jButton1); slider.setValue(10); topPanel.add(slider); bottomPanel.setLayout(new FlowLayout()); bottomPanel.add(jLabel2); bottomPanel.add(cTextField); bottomPanel.add(jLabel3); bottomPanel.add(sTextField); bottomPanel.add(jLabel4); bottomPanel.add(bTextField); // bottomPanel.add(jLabel5);////// // bottomPanel.add(dTextField);////// this.getContentPane().setLayout(new BorderLayout()); this.getContentPane().add(topPanel,BorderLayout.NORTH); this.getContentPane().add(vp,BorderLayout.CENTER); this.getContentPane().add(bottomPanel,BorderLayout.SOUTH); this.setSize(640,480); this.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e) { System.exit(0); } }); } public static void main(String[] args) { // TODO code application logic here MainFrame mf = new MainFrame("MVC练习 "); mf.setVisible(true); } }
2.视图.位于包com.view下,全路径com.view.*
/* * BTextField.java */ package com.view; import com.util.ObserverInterface; import java.text.DecimalFormat; import javax.swing.JTextField; import com.model.CircleModel; public class BTextField extends JTextField implements ObserverInterface{ private CircleModel model; private DecimalFormat df = new DecimalFormat("######0.00"); /** Creates a new instance of RTextField */ public BTextField() { } public BTextField(CircleModel model){ super(10); this.model = model; this.update(); } public void dataUpdate(CircleModel cm) { this.setModel(getModel()); update(); } private void update(){ this.setText(df.format(model.computeBallSuperficial())); } public CircleModel getModel() { return model; } public void setModel(CircleModel model) { this.model = model; } }
/* * ControlSlider.java */ package com.view; import com.controller.Controller; import com.util.ObserverInterface; import java.text.DecimalFormat; import javax.swing.JSlider; import javax.swing.JTextField; import com.model.CircleModel; /** * */ public class ControlSlider extends JSlider implements ObserverInterface{ private CircleModel circleModel; /** Creates a new instance of ControlSlider */ public ControlSlider() { } public ControlSlider(CircleModel circleModel){ super(0,Controller.MAXRADII,(int)circleModel.getRadii()); this.circleModel = circleModel; } public void dataUpdate(CircleModel circleModel) { setCircleModel(circleModel); setValue((int)Math.round(circleModel.getRadii())); } public CircleModel getCircleModel() { return circleModel; } public void setCircleModel(CircleModel circleModel) { this.circleModel = circleModel; } }
/* * CTextField.java */ package com.view; import com.util.ObserverInterface; import java.text.DecimalFormat; import javax.swing.JTextField; import com.model.CircleModel; /** * */ public class CTextField extends JTextField implements ObserverInterface{ private CircleModel model; private DecimalFormat df = new DecimalFormat("#####0.00"); /** Creates a new instance of RTextField */ public CTextField() { } public CTextField(CircleModel model){ super(10); this.model = model; this.update(); } public void dataUpdate(CircleModel cm) { this.setModel(getModel()); update(); } private void update(){ this.setText(df.format(model.computeGirth())); } public CircleModel getModel() { return model; } public void setModel(CircleModel model) { this.model = model; } }
/* * RTextField.java * */ package com.view; import com.util.ObserverInterface; import java.text.DecimalFormat; import javax.swing.JTextField; import com.model.CircleModel; /** * */ public class RTextField extends JTextField implements ObserverInterface{ private CircleModel model; private DecimalFormat df = new DecimalFormat("#####0.0"); /** Creates a new instance of RTextField */ public RTextField() { } public RTextField(CircleModel model){ super(10); this.model = model; this.update(); } public void dataUpdate(CircleModel cm) { this.setModel(getModel()); update(); } private void update(){ this.setText(df.format(model.getRadii())); } public CircleModel getModel() { return model; } public void setModel(CircleModel model) { this.model = model; } }
/* * STextField.java * */ package com.view; import com.util.ObserverInterface; import java.text.DecimalFormat; import javax.swing.JTextField; import com.model.CircleModel; /** * */ public class STextField extends JTextField implements ObserverInterface{ private CircleModel model; private DecimalFormat df = new DecimalFormat("#####0.00"); /** Creates a new instance of RTextField */ public STextField() { } public STextField(CircleModel model){ super(10); this.model = model; this.update(); } public void dataUpdate(CircleModel cm) { this.setModel(getModel()); update(); } private void update(){ this.setText(df.format(model.computeSuperficial())); } public CircleModel getModel() { return model; } public void setModel(CircleModel model) { this.model = model; } }
/* * ViewPanel.java */ package com.view; import com.model.CircleModel; import com.util.ObserverInterface; import javax.swing.*; import java.awt.*; import javax.swing.border.*; /** * */ public class ViewPanel extends JPanel implements ObserverInterface{ private CircleModel model; /** Creates a new instance of ViewPanel */ public ViewPanel() { } public ViewPanel(CircleModel model){ this.setModel(model); vpInit(); } private void vpInit(){ // this.setBackground(Color.GRAY); this.setBorder(new TitledBorder(BorderFactory.createLineBorder(Color.blue,1),"视图区")); } public void paintComponent(Graphics g){ super.paintComponent(g); if(getModel()==null) return; double r = getModel().getRadii(); int w = this.getWidth(); int h = this.getHeight(); int x = (int)Math.round(r); // g.setColor(Color.BLUE); // g.fillOval(w/2-x,h/2-x,x+x,x+x); g.drawOval(w/2-x,h/2-x,x+x,x+x); } public void dataUpdate(CircleModel cm) { this.setModel(getModel()); repaint(); } public CircleModel getModel() { return model; } public void setModel(CircleModel model) { this.model = model; } }
//待添加的直径一栏 /* * TextField.java */ package com.view; import com.util.ObserverInterface; import java.text.DecimalFormat; import javax.swing.JTextField; import com.model.CircleModel; /** * */ public class DTextField extends JTextField implements ObserverInterface{ private CircleModel model; private DecimalFormat df = new DecimalFormat("#####0.00"); public DTextField() { } public DTextField(CircleModel model){ super(10); this.model = model; this.update(); } public void dataUpdate(CircleModel cm) { this.setModel(getModel()); update(); } private void update(){ this.setText(df.format(model.computeDiameter())); } public CircleModel getModel() { return model; } public void setModel(CircleModel model) { this.model = model; } }
3.控制器位于包com.controller下
/* * Controller.java */ package com.controller; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.JOptionPane; import java.text.DecimalFormat; import com.MainFrame; import com.view.ViewPanel; import com.model.CircleModel; /** * */ public class Controller implements ActionListener,ChangeListener{ public static final int MAXRADII = 500; private MainFrame mf; private CircleModel model; /** Creates a new instance of Controller */ public Controller() { } public Controller(MainFrame mf){ this.mf = mf; model = mf.model; //注册界面 model.registerObserver(mf.vp); model.registerObserver(mf.rTextField); model.registerObserver(mf.cTextField); model.registerObserver(mf.sTextField); model.registerObserver(mf.bTextField); // model.registerObserver(mf.dTextField); model.registerObserver(mf.slider); mf.jButton1.addActionListener(this); mf.slider.addChangeListener(this); } public void actionPerformed(ActionEvent actionEvent) { if(actionEvent.getSource().equals(mf.jButton1)){ try{ double r = Double.parseDouble(mf.rTextField.getText()); if(r>=0.0&&r<=MAXRADII){ mf.slider.removeChangeListener(this);//去除监听,防止发生值更改事件导致反复操作 model.changeRadii(r); mf.slider.addChangeListener(this); } else showMessageDialog("请输入正确的半径0.0-"+MAXRADII+".0"); }catch(Exception err){ showMessageDialog("请输入正确的半径0.0-"+MAXRADII+".0"); } } } public void stateChanged(ChangeEvent changeEvent) { double r = (double)mf.slider.getValue(); model.changeRadii(r); } public void showMessageDialog(String str){ JOptionPane.showMessageDialog(mf,str,"消息",JOptionPane.INFORMATION_MESSAGE); } }
4.模型位于com.model下
/* * CircleModel.java * * 圆的模型。 */ package com.model; import java.util.ArrayList; import java.util.Iterator; import com.util.ObserverInterface; public class CircleModel { private double radii = 10.0;//半径 private ArrayList observer = new ArrayList();//观察者列表 /** Creates a new instance of CircleModel */ public CircleModel() { super(); } public CircleModel(double radii){ setRadii(radii); } public double getRadii() { return radii; } public void setRadii(double radii) { this.radii = radii; } /** * 计算周长 */ public double computeGirth(){ return (radii*Math.PI*2.0); } /** * 计算面积 */ public double computeSuperficial(){ return (radii*radii*Math.PI); } public double computeBallSuperficial(){ return (radii*radii*4*Math.PI); } public double computeDiameter(){ return 2*radii; } /** * 向模型中登记观察者 */ public void registerObserver(ObserverInterface o){ observer.add(o); } public void removeObserver(ObserverInterface o){ observer.remove(o); } /** * 当数据改变时,由控制器调用,通知各个观察者,改变视图 */ public void changeRadii(double r){ setRadii(r); dataUpdate(); } private void dataUpdate() { for(Iterator i = observer.iterator(); i.hasNext();){ ObserverInterface o = (ObserverInterface)(i.next()); o.dataUpdate(this); } } }
5.最后一个接口工具包,位于com.util
/* * ObserverInterface.java * * 公共接口,观察者。 */ package com.util; import com.model.CircleModel; public interface ObserverInterface { public void dataUpdate(CircleModel cm); }
四.截图
1.未添加直径一栏前
2.添加直径一栏,具体代码改动请见之前代码注释部分
五.源代码下载