MVC

mvc是什么

軟體架構模式中,MVC是開發者耳熟能詳的,然而由於Web應用程式的流行,今日多數開發者談及MVC聯想到的,其實是Model 2。

基本上,MVC與Model 2都是將系統畫分為Model、View和Controller三個部份,最大不同在於Model與View間的互動方式,隨著軟、硬體技術的進化與應用程式規模的擴展,MVC/Model 2的應用方式也在調整、改變與結合。

维基百科(传统桌面mvc模式)

MVC模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

  • 控制器: 负责请求转发,对请求进行处理

  • 视图: 界面人员进行图形界面设计

  • 模型: 程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)。

组件

  • 模型(Model)

用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“ Model ”有对数据直接访问的权力,例如对数据库的访问。“Model”不依赖“View”和“Controller”,也就是说, Model 不关心它会被如何显示或是如何被操作。但是 Model 中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此 Model 的 View 必须事先在此 Model 上注册,从而,View 可以了解在数据 Model 上发生的改变。(比较:观察者模式(软件设计模式))

  • 视图(View)

能够实现数据有目的的显示(理论上,这不是必需的)。在 View 中一般没有程序上的逻辑。为了实现 View 上的刷新功能,View 需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。

  • 控制器(Controller)

起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据 Model 上的改变。

练习

心脏起搏器

代码


package heart_driver; 

public class HeartDriver {     

    public static void main(String[] args) {         

        new HeartDriver();     

    } 

        public HeartDriver() {

                Controller controller = new Controller(); 

                Model model = new Model(); 

                View view = new View();

                view.setController(controller); 

                controller.setModel(model); 

                controller.setView(view); 

                model.addHeartBeatListener(view); 

                view.slider.setValue(75); model.frequency = 75; } 

}

Model


package heart_driver;



import java.util.ArrayList;



interface HeartBeatListener {

    public void onHeartBeat();

}




class Model {



    int frequency;

    boolean on;

    ArrayList<HeartBeatListener> listeners = new ArrayList<>();

    public void addHeartBeatListener(HeartBeatListener listener) {

        listeners.add(listener);

    }

    public void removeHeartBeatListener(HeartBeatListener listener) {

        listeners.remove(listener);

    }

    public void setFrequency(int freq) {

        this.frequency = freq;

    }

    public void on() {

        on = true;

        new Thread(new Runnable() {         

            @Override

            public void run() {

                while(on) {

                    for(HeartBeatListener listener : listeners)

                        listener.onHeartBeat();

                    try {

                        Thread.sleep(60000/frequency);

                    } catch (InterruptedException e) {}

                }



            }

        }).start();     

    }

    public void off() {

        on = false;

    }

}

View


package heart_driver;



import java.awt.BorderLayout;

import java.awt.Color;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;



import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JPanel;

import javax.swing.JProgressBar;

import javax.swing.JSlider;

import javax.swing.event.ChangeEvent;

import javax.swing.event.ChangeListener;



class View extends JFrame implements HeartBeatListener,ActionListener,ChangeListener {



    Controller controller;

    JButton onButton,offButton;

    JSlider slider;

    JProgressBar bar;



    public View() {



        JPanel buttonPanel = new JPanel();

        onButton = new JButton("on");

        offButton = new JButton("off");

        onButton.addActionListener(this);

        offButton.addActionListener(this);

        buttonPanel.add(onButton);

        buttonPanel.add(offButton);

        add(buttonPanel,BorderLayout.NORTH);



        bar = new JProgressBar();

        bar.setForeground(Color.RED);

        add(bar,BorderLayout.CENTER);



        slider = new JSlider();

        slider.setMaximum(200);

        slider.setMinimum(1);

        slider.setValue(70);

        slider.addChangeListener(this);

        JPanel sliderPanel = new JPanel();

        sliderPanel.add(new JLabel("频率:"));

        sliderPanel.add(slider);

        add(sliderPanel,BorderLayout.SOUTH);



        pack();

        setDefaultCloseOperation(EXIT_ON_CLOSE);

        setTitle("心脏起搏器");

        off();

        setVisible(true);

    }

    public void setController(Controller controller) {

        this.controller = controller;

    }

    public void on() {

        offButton.setEnabled(true);

        onButton.setEnabled(false);

    }

    public void off() {

        offButton.setEnabled(false);

        onButton.setEnabled(true);

    }

    @Override

    public void onHeartBeat() { 

        try {

            for(int i=0;i<bar.getMaximum();i+=bar.getMaximum()/5) {

                bar.setValue(i);

                Thread.sleep(20);           

            }

            for(int i=bar.getMaximum();i>=0;i-=bar.getMaximum()/5) {

                bar.setValue(i);

                Thread.sleep(20);

            }

        } catch (InterruptedException e) {}             

    }

    @Override

    public void stateChanged(ChangeEvent e) {

        int freq = ((JSlider)e.getSource()).getValue();

        controller.setFrequency(freq);

    }

    @Override

    public void actionPerformed(ActionEvent e) {

        if(e.getSource()==onButton) 

            controller.on();

        else if(e.getSource()==offButton)

            controller.off();

    }

}

Controller


package heart_driver;



class Controller {



    View view;

    Model model;

    public void setView(View view) {

        this.view = view;

    }

    public void setModel(Model model) {

        this.model = model;

    }

    public void setFrequency(int freq) {

        model.setFrequency(freq);

    }

    public void on() {

        view.on();

        model.on();

    }

    public void off() {

        view.off();

        model.off();

    }

}

优缺点

优点

  • 由controller协调,view不会直接对model做出任何变更,view只负责呈现逻辑,即根据model资料呈现结果,相关操作对应的业务逻辑不在view中。因此可以用不同的呈现方式,gui , console

  • controller负责商务逻辑中请求参数的收集与检验,更复杂的业务逻辑交给model处理,使得controller维持轻巧,model也有较高的重用性,controller也负责调配对应的view,所以model不会与view耦合。

  • Model不會知道或決定View實際呈現方式,因此View可以獨立於Model,自由變化。

  • Model狀態有變化時,曾向Model註冊過的多個View,都可獲得通知而得到同步更新效果。

第三項也許是最重要的優點,相較於Controller與Model來說,View相對來說最常變化,畢竟使用者往往對操作畫面要求最多也最善變,將Model與View切割後,Model就可以相對穩定地進行發展;而且View往往會由專門的使用者介面設計者負責,可能是專門的美術或設計師,未必擅長實際採用的技術,但可透過工具進行介面設計,讓View可以獨立於技術成份重的Model,自由變化,有助於團隊成員間的分工合作。

其他

Model2模式

軟體架構模式中,MVC是開發者耳熟能詳的,然而由於Web應用程式的流行,今日多數開發者談及MVC聯想到的,其實是Model 2。

基本上,MVC與Model 2都是將系統畫分為Model、View和Controller三個部份,最大不同在於Model與View間的互動方式,隨著軟、硬體技術的進化與應用程式規模的擴展,MVC/Model 2的應用方式也在調整、改變與結合。

實際上MVC模式本身並沒有明確定義,因而採納MVC模式中最大特徵「將系統畫分為Model、View和Controller三個部份」,並將三個部份的互動流程因實際應用場合進行調整,都可說是一種MVC模式,其中最為人熟悉的,就是Web應用程式經常採用的Model 2,又稱Web MVC,或由於過於流行而直接稱MVC了。

Web應用程式先天上,會被畫分為Model、View和Controller三個部份,View通常是客戶端的瀏覽器依取得的HTML繪製畫面,Controller位於Web伺服器,與資料庫互動的則是Model;傳統MVC模式實作的桌面應用程式,MVC三個部份通常位於同臺電腦,或者是透過持續網路連線互動。

然而,對於基於HTTP的Web應用程式來說,由於HTTP基於請求/回應(Request/Response)模型,沒有請求就不會有回應,因此無法實現傳統MVC中Model主動通知View的流程,如果View想根據Model最新狀態來呈現畫面,基本作法之一,是透過持續性地主動詢問(Poll)伺服端Model來達成。

基於HTTP限制而調整傳統MVC互動流程,得到的模式稱為Model 2,除了Model無法主動View外,基本上它的優點與傳統MVC前三項優點是相同的。

Model 2概念最早出現在1998年JSP規格書0.92版中,規格書中提及兩個模型,第一個模型稱為Model 1(因為文件提及的順序),第二個模型稱為Model 2。1999年Govind Seshadri在Javaworld發表了《Understanding JavaServer Pages Model 2 architecture》文章,其影響之一是將Model 2界定為架構模式,第二個影響是確立Model 2為Web應用程式提供了一種MVC架構。

Model 1中通常會將請求發給某個網頁動態元件(例如JSP或Servlet),由它處理請求參數收集、驗證、商務處理以及畫面回應,有些商務邏輯亦可能會封裝成Model(例如JavaBean),然而前端元件亦要處理請求參數收集、驗證與畫面回應,程式碼與畫面設計勢必形成義大利麵式的混亂,也因而Model 1通常應用在規模較小、任務簡單的Web應用程式。

mvc 与 model2的异同

儘管由於HTTP模型限制,使得Model 2無法達成傳統MVC中Model主動通知View的流程,然而MVC與Model 2有許多相似點,除了系統同被畫分為Model、View和Controller三個部份之外,Model 2中通常根據URL模式(Pattern)決定哪個Controller要接收View發送的請求參數,實際上在傳統MVC中,Controller名稱與方法簽署(Method signature)就相當於Model 2的URL模式,而方法的參數名稱與實際接收的引數,就相當HTTP請求中的參數名稱與值。

舉例來說,在實現Model 2時可定義從/messages/view?bid=34&id=123,決定使用MessagesController的view方法來處理bid與id請求參數;相對地,若有個桌面應用程式,畫面操作時若呼叫messagesController.view(bid, id),則messagesController變數結合view方法簽署,就相當於Model 2中URL模式,而bid與id變數就相當於請求參數。Web應用程式的網頁會設定發送表單的動作(action)對象,桌面應用程式會設定按鈕操作時呼叫的Controller與方法,兩者的意義實際是相同的。

隨著Ajax技術廣泛應用,以及伺服端非同步處理技術的進步,由於HTTP模型而造成的限制亦逐漸被克服。Web應用程式中為了取得Model最新狀態,即使使用傳統的持續詢問方式,已不再需要重清(Refresh)整個頁面,可利用Ajax在背景取得代表Model狀態的中性資料,而後用JavaScript更新畫面上相應的部分即可。

如果要作到更接近主動通知的概念,也就是在Model狀態有變化時,View可立即得到更新,伺服端可保留一定數量非同步請求,暫不回應,一旦Model狀態變化再進行回應,效果上就可達到傳統MVC模型中Model主動通知View的流程。

聊聊多样化的mvc/model2

隨著JavaScript、DOM、Ajax應用日漸廣泛,甚至HTML5新API的推波助瀾,同一Web應用程式中實現傳統MVC與Model 2的場合,越來越常見。

傳統Web應用程式中View原本由伺服端產生相關畫面,現在轉移給瀏覽器更動態的呈現,瀏覽器亦可有自成一體的應用程式,由HTML、DOM、CSS作為View的實現,JavaScript用以實現Controller與Model,就能在瀏覽器中實現傳統MVC模式應有流程,瀏覽器中JavaScript撰寫的Model,可將伺服端比擬為資料庫,向伺服端取得資料,就像對資料庫查詢,Ajax是與伺服端溝通的機制,伺服端傳回的資料,可能是中性格式、HTML或CSS組成的畫面片段,甚至是一段待執行的JavaScript程式碼。

無論如何,傳統Model 2中View的職責減輕了,這有助於開發者職責的畫分。過去由伺服端產生所有回應畫面的情境下,網頁設計師雖可獨立於Model設計畫面,但使用的元件仍會與伺服端技術有關(像是JSTL自訂標籤等),如果採用的伺服端技術不同,設計師就得學習使用不同的元件。

當原本伺服端的View將組織畫面的職責卸下,交給瀏覽器處理之後,設計師可專心使用瀏覽器上的JavaScript、DOM、CSS等相關技術,只要協調好與伺服端的資料交換格式,設計師甚至可以先行製作假資料,完全獨立於伺服端工作進度之外,完成自身任務。

引用

mvc是一个巨大的误会

技术名字纷争多

心脏起搏器

MVC与Model2的变异与结合

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值