HelloWorld 善戰(zhàn)者,求之于勢(shì),不責(zé)于人;故能擇人而任勢(shì)。

          知止而后有定,定而后能靜,靜而后能安,安而后能慮,慮而后能得。物有本末,事有終始。知所先后,則近道矣。

            BlogJava :: 首頁(yè) ::  :: 聯(lián)系 ::  :: 管理 ::
            167 隨筆 :: 1 文章 :: 40 評(píng)論 :: 0 Trackbacks

          實(shí)戰(zhàn)MVC模式

          MVC

          “模型-視圖-控制器(Model-View-Controller,MVC)結(jié)構(gòu)是為那些需要為同樣的數(shù)據(jù)提供多個(gè)視圖的應(yīng)用程序而設(shè)計(jì)的,它很好的實(shí)現(xiàn)了數(shù)據(jù)層與表示層的分離。例如下圖中的例子:

           

          MVC

          我們看到,圖中的幾組數(shù)據(jù)以不同的形式(View)表現(xiàn)出來(lái),一個(gè)是表格樣式,一個(gè)是圖形樣式。

          MVC通信方式

          MVC把這種應(yīng)用程序分為三種對(duì)象類型:

           

          • 模型:維護(hù)數(shù)據(jù)并提供數(shù)據(jù)訪問(wèn)方法。
          • 視圖:給制模型的部分?jǐn)?shù)據(jù)或所有數(shù)據(jù)的可視圖。
          • 控制器:處理事件.

          以下是典型的MVC通信方式,

          [{MVC_1.gif][MVC的通信方式]]

          1. 事件由控制器來(lái)處理,控制器接收用戶事件,并根據(jù)事件的類型來(lái)改變模型。
          2. 視圖事先會(huì)在模型中登記,當(dāng)模型數(shù)據(jù)發(fā)生改變時(shí),馬上通知已向此模型登記的每個(gè)視圖。
          3. 視圖從模取得最新的數(shù)據(jù)并刷新自己.

          要實(shí)現(xiàn)MVC,最重要的一個(gè)環(huán)節(jié)是使用Design Pattern中的Observer模式。Observer模式允許某個(gè)對(duì)象在所觀察的對(duì)象發(fā)生修改時(shí)通知多個(gè)觀察者(Observer).

          下面我們就以實(shí)例來(lái)講解如何用Obserer模式實(shí)現(xiàn)MVC的程序結(jié)構(gòu)。在我的例子中,我要實(shí)現(xiàn)一個(gè)學(xué)生年齡顯示的例子。分別用清單和圖形的方式顯示每個(gè)學(xué)生的年齡。當(dāng)年齡改變時(shí),自動(dòng)更新顯示。

          Observer接口

          為了實(shí)現(xiàn)觀察的對(duì)象發(fā)生修改時(shí)通知多個(gè)觀察者,通常要在被觀察者與觀察者之間有一個(gè)小的接口,如下:
          /* file: Observer.java */
          public interface Observer {
          public void dataUpdate(Model model);
          }
          

          這個(gè)接口中有一個(gè) dataUpdate(Model model) 方法,只要實(shí)現(xiàn)了這個(gè)接口對(duì)象,就成了一個(gè)觀察者。

          模型Model

          再來(lái)建立一個(gè)數(shù)據(jù)模型。在我的例子中,先建立了一個(gè)數(shù)據(jù)對(duì)象:

           

          /* file: Data.java */
          public class Data {
          public int value; // 學(xué)生年齡值
          
          public String name; // 學(xué)生名
          }
          

          現(xiàn)在來(lái)建立一個(gè) 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[i], name[i]);
          }
          }
          public Model(Data[] data) {
          for (int i = 0; i < data.length; i++) {
          addData(data[i]);
          }
          }
          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();
          }
          // 用來(lái)向模型中登記觀察者.
              public void registerObserver(Observer o) {
          observer.add(o);
          }
          public void removeObserver(Observer o) {
          observer.remove(o);
          }
          // 當(dāng)數(shù)據(jù)改變時(shí),由Controller調(diào)用此方法,通知各個(gè)Observer,刷新視圖.
              public void changeModel(Model model) {
          data.clear();
          for (int i = 0; i < model.size(); 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);
          }
          }
          }
          

          這個(gè)模型提供各種數(shù)據(jù)訪問(wèn)的方法。并提供一個(gè) changeModel(Model model) 方法供 Controller 訪問(wèn)。還提供一個(gè) registerObserver(Observer o) 方法,用來(lái)向 Model 中登記觀察者 Observer

          視圖View

          我們要實(shí)現(xiàn)一個(gè)清單顯示樣式的視圖 View1 和一個(gè)圖形方式顯示的視圖 View2 ,并讓它們實(shí)現(xiàn) Observer 接口,以便當(dāng) Model 數(shù)據(jù)改變時(shí),自動(dòng)刷新自己.
          /* 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;
          }
          }
          // 當(dāng)模型數(shù)據(jù)發(fā)生改變時(shí),會(huì)自動(dòng)調(diào)用此方法來(lái)刷新圖形
              public void dataUpdate(Model model) {
          /** @todo: Implement this Observer method */
          this.model = model;
          repaint();
          }
          }
          

          View2.java

          /* 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 < value; j++) {
          g.setColor(c);
          g.drawOval(cx, cy, r, r);
          r += dx;
          }
          g.drawString(data.name, 25, cy);
          }
          }
          // 當(dāng)模型數(shù)據(jù)發(fā)生改變時(shí),會(huì)自動(dòng)調(diào)用此方法來(lái)刷新圖形
              public void dataUpdate(Model model) {
          /** @todo: Implement this Observer method */
          this.model = model;
          repaint();
          }
          }
          

          控制器Controller

          好了,MVC中的 Model , Observer 都建立好了,我們最后來(lái)做一個(gè) Controller :

           

          import java.awt.*;
          import javax.swing.*;
          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, 208));
          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數(shù)據(jù)發(fā)生改變.
              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);
          }
          }
          

          運(yùn)行程序

          各位可以將這些代碼各自存為相應(yīng)的源文件,執(zhí)行以下命令編譯

          javac Controller.java

          運(yùn)行

          java Controller.class

          就可以看到程序執(zhí)行的效果,

          執(zhí)行結(jié)果示圖

          你可以試著改變兩個(gè)學(xué)生的年齡,按一下 Update 按鈕,相應(yīng)的視圖就更新了。怎么樣,體驗(yàn)到了MVC結(jié)構(gòu)給程序帶來(lái)的方便性了吧?;)

          大家如果運(yùn)行程序有任何問(wèn)題,或需編譯好的程序,可與我聯(lián)絡(luò)。

          關(guān)于作者

          陳先波(turbochen)是賽微科技公司(www.qissoft.com)的Java開(kāi)發(fā)員,曾為多個(gè)技術(shù)網(wǎng)站撰稿。有超過(guò)三年的Java開(kāi)發(fā)經(jīng)驗(yàn),主要致力于Java技術(shù)在質(zhì)量管理信息系統(tǒng)中的應(yīng)用,請(qǐng)通過(guò)turbochen@163.com與作者聯(lián)系。

          </script>

          posted on 2008-02-15 15:26 helloworld2008 閱讀(184) 評(píng)論(0)  編輯  收藏 所屬分類: java
          主站蜘蛛池模板: 石景山区| 花莲县| 兴安县| 长子县| 朝阳市| 石嘴山市| 威信县| 会泽县| 敖汉旗| 郯城县| 永兴县| 师宗县| 云阳县| 黄梅县| 延边| 湘西| 鄯善县| 梧州市| 桓台县| 临猗县| 葵青区| 罗城| 丹棱县| 临武县| 龙井市| 枣强县| 澳门| 达尔| 托克逊县| 和田市| 许昌县| 呈贡县| 四子王旗| 万州区| 长海县| 泸溪县| 红原县| 曲麻莱县| 常山县| 安仁县| 永德县|