?內容:
1.MVC
2.Observer接口
3.模型Model
4.視圖View
5.控制器Controller
6.運行程序??
--------------------------------------------------------------------------------
MVC
“模型-視圖-控制器(Model-View-Controller,MVC)結構是為那些需要為同樣的數據提供多個視圖的應用程序而設計的,它很好的實現了數據層與表示層的分離。例如下圖中的例子:

我們看到,圖中的幾組數據以不同的形式(View)表現出來,一個是表格樣式,一個是圖形樣式。
MVC把這種應用程序分為三種對象類型:
模型:維護數據并提供數據訪問方法。
視圖:給制模型的部分數據或所有數據的可視圖。
控制器:處理事件.
以下是典型的MVC通信方式,

事件由控制器來處理,控制器接收用戶事件,并根據事件的類型來改變模型。
視圖事先會在模型中登記,當模型數據發生改變時,馬上通知已向此模型登記的每個視圖。
視圖從模取得最新的數據并刷新自己.
要實現MVC,最重要的一個環節是使用Design??Pattern中的Observer模式。Observer模式允許某個對象在所觀察的對象發生修改時通知多個觀察者(Observer).
下面我們就以實例來講解如何用Obserer模式實現MVC的程序結構。在我的例子中,我要實現一個學生年齡顯示的例子。分別用清單和圖形的方式顯示每個學生的年齡。當年齡改變時,自動更新顯示。
Observer接口
為了實現觀察的對象發生修改時通知多個觀察者,通常要在被觀察者與觀察者之間有一個小的接口,如下:
/*??file:??Observer.java??*/
public??interface??Observer
{
????????public??void??dataUpdate(Model??model);
}
這個接口中有一個dataUpdate(Model??model)方法,只要實現了這個接口對象,就成了一個觀察者。
模型Model
再來建立一個數據模型。在我的例子中,先建立了一個數據對象:
/*??file:??Data.java??*/
public??class??Data
{
????????public??int??value; //??學生年齡值
????????public??String??name; //??學生名
}
現在來建立一個Model:
/*??file:??Model.java??*/
import??java.util.*;
public??class??Model
{
????????ArrayList??data??=??new??ArrayList();
????????ArrayList??observer??=??new??ArrayList();
????????public??Model()
????????{????????super();
????????}
????????public??Model(int[]??value,??String[]??name)
????????{
????????????????for??(??int??i??=??0;??i<??value.length;??i++??
????????????????{
????????????????????????addData(value
,name);
????????????????}
????????}
????????public??Model(Data[]??data)
????????{
????????????????for??(??int??i??=??0;??i<??data.length;??i++??
????????????????{
????????????????????????addData(data);
????????????????}
????????}
????????public??void??addData(int??value,??String??name)
????????{
????????????????Data??data??=??new??Data();
????????????????data.value??=??value;
????????????????data.name??=??name;
????????????????this.data.add(data);
????????}
????????public??void??addData(Data??data)
????????{
????????????????this.data.add(data);
????????}
????????public??Data??getData(int??idx)
????????{
????????????????return??(Data)(data.get(idx));
????????}
????????public??int??size()
????????{
????????????????return??data.size();
????????}
//??用來向模型中登記觀察者.
????????public??void??registerObserver(Observer??o)
????????{
????????????????observer.add(o);
????????}
????????public??void??removeObserver(Observer??o)
????????{
????????????????observer.remove(o);
????????}
????????//??當數據改變時,由Controller調用此方法,通知各個Observer,刷新視圖.
????????public??void??changeModel(Model??model)
????????{
????????????????data.clear();
????????????????for??(int??i=0;??i
????????????????{
????????????????????????this.addData(model.getData(i));
????????????????}
????????????????dataUpdate();
????????}
????????private??void??dataUpdate()
????????{
????????????????for??(Iterator??i??=??observer.iterator();??i.hasNext();??
????????????????{
????????????????????????Observer??o??=??(Observer)(i.next());
????????????????????????o.dataUpdate(this);
????????????????}
????????}
}
這個模型提供各種數據訪問的方法。并提供一個changeModel(Model??model)方法供Controller訪問。還提供一個registerObserver(Observer??o)方法,用來向Model中登記觀察者Observer。
視圖View
我們要實現一個清單顯示樣式的視圖View1和一個圖形方式顯示的視圖View2,并讓它們實現Observer接口,以便當Model數據改變時,自動刷新自己.
/*??file:??View1.java??*/
import??javax.swing.*;
import??java.awt.*;
import??javax.swing.border.*;
public??class??View1??extends??JPanel??implements??Observer
{
????????Model??model;
????????public??View1()
????????{
????????}
????????public??View1(Model??model)
????????{
????????????????try
????????????????{
????????????????????????this.model??=??model;
????????????????????????jbInit();
????????????????}
????????????????catch(Exception??e)
????????????????{
????????????????????????e.printStackTrace();
????????????????}
????????}
????????private??void??jbInit()??throws??Exception
????????{
????????????????this.setBackground(Color.white);
????????????????this.setBorder(new??TitledBorder(BorderFactory.createLineBorder(Color.black,1),"View1");
????????}
????????public??void??paintComponent(Graphics??g)
????????{
????????????????super.paintComponent(g);
????????????????if??(??model??==??null????return;
????????????????int??x??=??20,y??=??50;
????????????????int??h??=??g.getFontMetrics().getHeight();
????????????????for??(??int??i=0;??i<??model.size();??i++??
????????????????{
????????????????????????Data??data??=??model.getData(i);
????????????????????????g.drawString(data.name,x,y);
????????????????????????y+=h;
????????????????????????g.drawString(String.valueOf(data.value),x,y);
????????????????????????y+=h;
????????????????}
????????}
????????//??當模型數據發生改變時,會自動調用此方法來刷新圖形
????????public??void??dataUpdate(Model??model)
????????{
????????????????/**@todo:??Implement??this??Observer??method*/
????????????????this.model??=??model;
????????????????repaint();
????????}
}
/*??file:??View2.java??*/
import??javax.swing.*;
import??java.awt.*;
import??javax.swing.border.*;
public??class??View2??extends??JPanel??implements??Observer
{
????????Model??model;
????????public??View2()
????????{
????????}
????????public??View2(Model??model)
????????{
????????????????try
????????????????{
????????????????????????this.model??=??model;
????????????????????????jbInit();
????????????????}
????????????????catch(Exception??e)
????????????????{
????????????????????????e.printStackTrace();
????????????????}
????????}
????????private??void??jbInit()??throws??Exception
????????{
????????????????this.setBackground(Color.white);
????????????????this.setBorder(new??TitledBorder(BorderFactory.createLineBorder(Color.black,1),"View1");
????????}
????????public??void??paintComponent(Graphics??g)
????????{
????????????????super.paintComponent(g);
????????????????if??(??model??==??null????return;
????????????????int??x??=??20,y??=??50;
????????????????int??h??=??g.getFontMetrics().getHeight();
????????????????int??width??=??this.getWidth();
????????????????int??height??=??this.getHeight();
????????????????int??sy??=??height??/??model.size();
????????????????int??sx??=??width/??2;
????????????????for??(??int??i=0;??i<??model.size();??i++??
????????????????{
????????????????????????Data??data??=??model.getData(i);
????????????????????????int??value??=??data.value;
????????????????????????int??dx??=??3;
????????????????????????int??r??=??3;
????????????????????????Color??c??=??new??Color((int)(255*Math.random()),(int)(255*Math.random()),(int)(255*Math.random()));
????????????????????????int??cx??=??sx;
????????????????????????int??cy??=??y+i??*??sy;
????????????????????????for??(??int??j=0;j
????????????????????????{
????????????????????????????????g.setColor(c);
????????????????????????????????g.drawOval(cx,cy,r,r);
????????????????????????????????r+=dx;
????????????????????????}
????????????????????????g.drawString(data.name,25,cy);
????????????????}
????????}
????????//??當模型數據發生改變時,會自動調用此方法來刷新圖形
????????public??void??dataUpdate(Model??model)
????????{
????????????????/**@todo:??Implement??this??Observer??method*/
????????????????this.model??=??model;
????????????????repaint();
????????}
}
控制器Controller
好了,MVC中的Model,Observer都建立好了,我們最后來做一個Controller:
import??java.awt.*;
import??javax.swing.*;
import??javax.swing.border.*;
import??java.awt.event.*;
public??class??Controller??extends??JFrame
{
????????Model??model??=????new??Model();
????????View1??view1??=??new??View1(model);
????????View2??view2??=??new??View2(model);
????????JScrollPane??jScrollPane1??=??new??JScrollPane();
????????JButton??jButton1??=??new??JButton();
????????JTextField??jTextField1??=??new??JTextField();
????????JTextField??jTextField2??=??new??JTextField();
????????JLabel??jLabel1??=??new??JLabel();
????????JLabel??jLabel2??=??new??JLabel();
????????JLabel??jLabel3??=??new??JLabel();
????????public??Controller()
????????{
????????????????try
????????????????{
????????????????????????jbInit();
????????????????}
????????????????catch(Exception??e)
????????????????{
????????????????????????e.printStackTrace();
????????????????}
????????}
????????private??void??jbInit()??throws??Exception
????????{
????????????????Data[]??data??=??new??Data[2];
????????????????data[0]??=??new??Data();
????????????????data[1]??=??new??Data();
????????????????data[0].name??=??"Ted";
????????????????data[0].value??=??20;
????????????????data[1].name??=??"Joy";
????????????????data[1].value??=??14;
????????????????model.addData(data[0]);
????????????????model.addData(data[1]);
????????????????//??注意下面兩行:向模型中登記它的觀察者View1和View2.
????????????????model.registerObserver(view1);
????????????????model.registerObserver(view2);
????????????????this.getContentPane().setLayout(null);
????????????????jScrollPane1.setBounds(new??Rectangle(0,??0,??3,??3));
????????????????jButton1.setBounds(new??Rectangle(309,??259,??101,??27));
????????????????jButton1.setText("Update";
????????????????jButton1.addActionListener(new??java.awt.event.ActionListener()
????????????????{
????????????????????????public??void??actionPerformed(ActionEvent??e)
????????????????????????{
????????????????????????????????jButton1_actionPerformed(e);
????????????????????????}
????????????????});
????????????????jTextField1.setText("20";
????????????????jTextField1.setBounds(new??Rectangle(80,??254,??52,??30));
????????????????jTextField2.setText("14";
????????????????jTextField2.setBounds(new??Rectangle(178,??255,??50,??31));
????????????????jLabel1.setText("Age:";
????????????????jLabel1.setBounds(new??Rectangle(41,??226,??47,??23));
????????????????jLabel2.setText("Ted";
????????????????jLabel2.setBounds(new??Rectangle(42,??252,??35,??33));
????????????????jLabel3.setText("Joy";
????????????????jLabel3.setBounds(new??Rectangle(144,??255,??31,??31));
????????????????view1.setBounds(new??Rectangle(7,??5,??225,??20);
????????????????view2.setBounds(new??Rectangle(234,??4,??219,??209));
????????????????this.getContentPane().add(jScrollPane1,??null);
????????????????this.getContentPane().add(jTextField2,??null);
????????????????this.getContentPane().add(jTextField1,??null);
????????????????this.getContentPane().add(jLabel2,??null);
????????????????this.getContentPane().add(jLabel3,??null);
????????????????this.getContentPane().add(jLabel1,??null);
????????????????this.getContentPane().add(jButton1,??null);
????????????????this.getContentPane().add(view1,??null);
????????????????this.getContentPane().add(view2,??null);
????????}
????????//??按下Update按鈕,通知Model數據發生改變.
????????void??jButton1_actionPerformed(ActionEvent??e)
????????{
????????????????Data[]??data??=??new??Data[2];
????????????????data[0]??=??new??Data();
????????????????data[1]??=??new??Data();
????????????????data[0].name??=??jLabel1.getText();
????????????????data[0].value??=??Integer.parseInt(jTextField1.getText());
????????????????data[1].name??=??jLabel2.getText();
????????????????data[1].value??=??Integer.parseInt(jTextField2.getText());
????????????????Model??m??=??new??Model(data);
????????????????this.model.changeModel(m);
????????}
????????public??static??void??main(String[]??args)
????????{
????????????????Controller??c??=??new??Controller();
????????????????c.setSize(475,310);
????????????????c.setVisible(true);
????????}
}
運行程序
各位可以將這些代碼各自存為相應的源文件,執行以下命令編譯
javac??Controller.java
運行
java??Controller.class
就可以看到程序執行的效果,
你可以試著改變兩個學生的年齡,按一下Update按鈕,相應的視圖就更新了。怎么樣,體驗到了MVC結構給程序帶來的方便性了吧?;