1. 程式人生 > >經典軟體體系結構風格(三)

經典軟體體系結構風格(三)

#模型-檢視-控制器風格常被簡稱為MVC風格

  --元件:模型、檢視、控制器

  --連線件:顯式呼叫、隱式呼叫、其他機制(例如:Http協議)

#工作機制:

 Model:

 --模型的職責

   1.負責資料存取

   2.負責業務邏輯實現

   3.負責資料驗證

#模型:模型是應用程式的核心。它封裝核心資料與狀態,對模型的修改將擴散到所有檢視中。所有需要從模型獲取資訊的物件都必須註冊為模型的檢視。

 在事件驅動系統,當資訊發生改變,模型通知觀察者(observers) (通常是檢視),從而引起檢視反應。

#View:

 檢視的職責:

–獲取使用者輸入

–向controller傳送處理請求

–接收來自Controller的反饋

–將model的處理結果顯示給使用者

  一個model可能有多個View

#Controller:

  控制器職責:

–接收來自客戶的請求

–呼叫model執行

–呼叫View顯示執行結果

  控制器:控制器是提供給使用者進行操作的介面。每個檢視與一個控制器元件相關聯。控制器接收使用者的輸入,通常是滑鼠移動、鍵盤輸入等。輸入事件翻譯成服務請求,送到模型或檢視。使用者只通過控制器與系統互動。

#兩個主要分離:

–模型與介面分離

–控制器與檢視分離

#優點:

–將各方面問題分解開來考慮,簡化了系統設計,保證了系統的可擴充套件性。

–改變介面不影響應用程式的功能核心,使得系統易於演化開發,可維護性好。

–同一資訊可以有不同的展現方式。

–業務邏輯更易測試

 # 案例


 程式碼:

CarModel.java(模型層)

package com.medel;
import java.io.*;
import java.net.URL;
import java.net.URI;
import javax.swing.*;

import com.view.View;

import java.util.*;

public class CarModel{
    private String[] carNameList;
    private URL imgURL;
    private URL carFileUrl;
    private ImageIcon imgIcon;
	private String carSelected;
    private String bitPrice;
    static final String CARFILES = "CarFiles/";
    static final String CARIMAGES = "CarImages/";

    public CarModel(){
        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 setupImageIcon(){
		    String iconStr = CARIMAGES + carSelected+".jpg";
	        imgIcon = createImageIcon(iconStr);
		}
    public ImageIcon getImageIcon(){
		    return imgIcon;
	}
	public void setCarFileURL(){
	    try{
		    String fileURLStr = CARFILES + carSelected+ ".html";
		    URI uri = (new File(fileURLStr)).toURI();
		    carFileUrl= uri.toURL();
		}
		catch (IOException e){
		    e.printStackTrace();
		}
	}
	public URL getCarFileURL(){
		return carFileUrl;
	}

    protected ImageIcon createImageIcon(String path){
       imgURL = getClass().getResource(path);
       if (imgURL != null) {
           return new ImageIcon(imgURL);
       } else {
           System.err.println("Couldn't find file: " + path);
           return null;
       }
   }
   public void tell(View view ){
	   view.update();
   }
} 

 檢視層:

View.java

package com.view;

public interface View {
  public abstract void update();
}

CarBitView.java

package com.view;
import java.awt.*;
import javax.swing.*;
import com.medel.CarModel;
public class CarBitView extends JFrame implements View{
    private JPanel showPanel;
    private JLabel bitOfferedLabel;
    private JTextArea bitText;
    private CarModel model;
    
	public CarBitView(CarModel cmodel) {
       super("Car Bit Info View- Observer 2");
       model = cmodel;

       bitOfferedLabel = new JLabel("Latest bit offered:");
       bitText = new JTextArea(4, 20);
       bitText.setFont(new Font("Serif", Font.PLAIN, 14));
       bitText.setLineWrap(true);
       bitText.setWrapStyleWord(true);

       Container contentPane = getContentPane();
       contentPane.add(bitOfferedLabel, BorderLayout.NORTH);
       contentPane.add(bitText, BorderLayout.CENTER);

       setSize(400, 150);
       setVisible(true);
     }

	 public void update(){
       System.out.println("Car bit has been called.");
       String sCar= model.getSelectedCar();
       String pr = model.getBitPrice();
       bitText.append("\n Bit price for "+ sCar + "="+ pr);
     }
}

CarGUIView.java
package com.view;
import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.net.URL;
import com.medel.CarModel;
public class CarGUIView extends JFrame implements View{
   private JEditorPane editorPane;
   private JScrollPane imagePane;
   private JScrollPane textPane;
   private JSplitPane splitPane;
   private JLabel imgLabel;
   private CarModel model;

   public CarGUIView(CarModel cmodel){
      super("視窗1--車的資訊");
	  model = cmodel;
      buildUpScrollGUI();
   }
   private void buildUpScrollGUI(){
      imgLabel = new JLabel();
      imgLabel.setBackground(Color.green);
	  imgLabel.setMinimumSize(new Dimension(250, 200));

      editorPane = new JEditorPane();
	  editorPane.setEditable(false);

      imagePane = new JScrollPane(imgLabel);
	  imagePane.getViewport().setBackground(Color.green);

	  textPane = new JScrollPane(editorPane);
	  textPane.setMinimumSize(new Dimension(250, 200));

	  splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
	  splitPane.setLeftComponent(imagePane);
	  splitPane.setRightComponent(textPane);

	  Dimension minimumSize = new Dimension(130, 100);
	  imagePane.setMinimumSize(minimumSize);
	  textPane.setMinimumSize(new Dimension(100, 100));
	  splitPane.setDividerLocation(160);
	  splitPane.setPreferredSize(new Dimension(500, 300));

	  Container contentPane = getContentPane();
	  contentPane.add(splitPane);
	  setSize(400, 150);
	  setVisible(true);
   }

    public void update(){
       try{
	      URL url = model.getCarFileURL();
          editorPane.setPage(url);
          System.out.println("We have been called.");
	   }
	   catch (IOException e){
	      e.printStackTrace();
       }
       ImageIcon imIcon = model.getImageIcon();
       imgLabel.setIcon(imIcon);
	   imgLabel.validate();
    }
}

 控制層:

Controller.java

package com.control;
import java.awt.event.*;
import javax.swing.*;

import com.medel.CarModel;
import com.view.CarBitView;
import com.view.CarGUIView;

import java.net.URL;
public class Controller implements ActionListener{
   private CarAuctionGUI objCarGui;
   private CarModel cm;
   private CarGUIView civ;
   private CarBitView cb;
   private String carPrice;
   private String[] carList;

   public Controller(CarAuctionGUI objCarGui,CarModel cm,
                     CarGUIView civ,CarBitView cb){
      this.objCarGui = objCarGui;
      this.cm=cm;
      this.civ=civ;
      this.cb=cb;

	  carList = objCarGui.getCarList();
	  cm.setCarList(carList);
   }
   public void actionPerformed(ActionEvent e){ 
      String searchResult = null;

      if (e.getActionCommand().equals(CarAuctionGUI.EXIT)){
         System.exit(1);
      }
      if (e.getActionCommand().equals(CarAuctionGUI.SEARCH)){
         String selectedCar = objCarGui.getSelectedCar();
         cm.setSelectedCar(selectedCar);
         cm.setCarFileURL();
         cm.setupImageIcon();
         cm.tell(civ);	//civ.update();
      }
      if (e.getActionCommand().equals(CarAuctionGUI.BIT)){
	     carPrice = objCarGui.getBitPrice();
		 cm.setBitPrice(carPrice);
         cm.tell(cb);		//cb.update();
	  }
   }
} 

CarAuctionGUI.java
package com.control;
import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.awt.event.*;
import com.medel.CarModel;
import com.view.CarBitView;
import com.view.CarGUIView;
public class CarAuctionGUI extends JPanel {
   private JTextField bitInputText;
   private JLabel lblCarModel;
   private JPanel buttonPanel;
   private String[] carList;
   private JComboBox cmbCarList;
   private static CarModel cm;
   private static CarGUIView civ;
   private static CarBitView cb;
   public static final String SEARCH = "尋找";
   public static final String BIT = "確定";
   public static final String EXIT = "退出";

   public CarAuctionGUI(){
   	   super(new GridLayout(1,0));
	   setUpGUI();
   }
   private void setUpGUI(){
      cmbCarList = new JComboBox();
      String[] cl = getCarList();
      setUpCarList(cl);
      lblCarModel = new JLabel("二手車種類及年份:");

      //Create the open button
      JButton srchButton = new JButton(SEARCH);
      srchButton.setMnemonic(KeyEvent.VK_S);
      JButton exitButton = new JButton(EXIT);
      exitButton.setMnemonic(KeyEvent.VK_X);
      JButton bitButton = new JButton(BIT);
      bitButton.setMnemonic(KeyEvent.VK_X);
      bitInputText = new JTextField("請輸入你想要的價格:",12);
      buttonPanel = new JPanel();

      //****************************************************
      GridBagLayout gridbag = new GridBagLayout();
      buttonPanel.setLayout(gridbag);
      GridBagConstraints gbc = new GridBagConstraints();

      buttonPanel.add(lblCarModel);
      buttonPanel.add(cmbCarList);
      buttonPanel.add(srchButton);
      buttonPanel.add(bitButton);
      buttonPanel.add(exitButton);
      buttonPanel.add(bitInputText);

      gbc.insets.top = 5;
      gbc.insets.bottom = 5;
      gbc.insets.left = 5;
      gbc.insets.right = 5;
      gbc.anchor = GridBagConstraints.EAST;
      gbc.gridx = 0;
      gbc.gridy = 0;
      gridbag.setConstraints(lblCarModel, gbc);
      gbc.anchor = GridBagConstraints.WEST;
      gbc.gridx = 1;
      gbc.gridy = 0;
      gridbag.setConstraints(cmbCarList, gbc);
      gbc.anchor = GridBagConstraints.EAST;
      gbc.insets.left = 2;
      gbc.insets.right = 2;
      gbc.insets.top = 25;
      gbc.anchor = GridBagConstraints.EAST;
      gbc.gridx = 0;
      gbc.gridy = 3;
      gridbag.setConstraints(srchButton, gbc);
      gbc.anchor = GridBagConstraints.WEST;
      gbc.gridx = 1;
      gbc.gridy = 3;
      gridbag.setConstraints(exitButton, gbc);
      gbc.gridx = 0;
	  gbc.gridy = 4;
      gridbag.setConstraints(bitButton, gbc);
      gbc.gridx = 1;
	  gbc.gridy = 4;
      gridbag.setConstraints(bitInputText, gbc);
      Controller objButtonHandler = new Controller(this,cm,civ,cb);
      srchButton.addActionListener(objButtonHandler);
      exitButton.addActionListener(objButtonHandler);
      bitButton.addActionListener(objButtonHandler);

      add(buttonPanel);
	  setSize(new Dimension(800, 450));
      setVisible(true);
    }

    public String getSelectedCar() {
	   return (String) cmbCarList.getSelectedItem();
	}

	public String getBitPrice(){
	   return	bitInputText.getText();
	}

	// get the names of all the .html files in a directory
	public String[] getCarList(){
	   File f = new File("CarFiles");
	   String [] fileNames = f.list();

	   for(int i=0; i<fileNames.length; i++ ){
	      int len = fileNames[i].length();
		  fileNames[i]=fileNames[i].substring(0,len-5);
	   }
	   return fileNames;
   }

	public void setUpCarList(String[] carList){
	   for(int k=0; k<carList.length; k++) {
	      cmbCarList.addItem(carList[k]);
	   }
	}

  private static void createAndShowGUI() {
     JFrame.setDefaultLookAndFeelDecorated(true);
     JFrame frame = new JFrame("MVC pattern demo");
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

     CarAuctionGUI newContentPane = new CarAuctionGUI();
     newContentPane.setOpaque(true);
     frame.setContentPane(newContentPane);

     //Display the window.
     frame.pack();
     frame.setVisible(true);
  }

  static public void main(String argv[]) {
	 javax.swing.SwingUtilities.invokeLater(new Runnable() {
     public void run() {
	    cm = new CarModel();
	    civ= new CarGUIView(cm);
	    cb = new CarBitView(cm);
        createAndShowGUI();
	 }
      });
  }
}