MVC模型简单解读

来源:互联网 发布:保留小数位数的函数sql 编辑:程序博客网 时间:2024/06/08 19:47

MVC简介 

  MVC全称为Model View Controller(模型-视图-控制器)。M是指业务模型,V是指用户界面,C则是控制器。MVC主要用于UI的相关设计中,它用业务逻辑数据界面显示分离的方法组织代码。使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据可以分别用柱状图饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。

要点

  1.MVC是有数个设计模式结合起来的。
  2.MVC结合了观察者模式策略模式组合模式
  3.模型使用观察者模式,以便观察者更新,同时保持两者之间解耦。
  4.视图为模型的观察者,同一个模式可以使用不同的视图,甚至可以同时使用多个视图。
  5.控制器是视图的策略,视图可以使用不同的控制器实现,得到不同的行为。
  6.控制器收到视图的数据后,会经过“解读”后再发送给模型。
  7.视图一般使用组合模式实现用户界面。

示意图

这里写图片描述

① 视图用于和用户交互
  视图是模型的窗口,当用户对视图操作后,视图就告诉控制器用户的操作,控制器会负责处理用户的请求。
  
② 控制器要求模型改变状态
  控制器解读用户的请求之后,便告知模型做出相应的动作。
  
③ 控制器也可能要求视图做改变
  当控制器收到视图的某一动作后,可能需要告诉视图做出相应的改变,比如界面上的某一个按钮变得无效。
  
④ 当模型状态改变时,模型会通知视图
  当模型的状态改变时(可能是因为用户的操作,也可能是模型自己内部状态的改变),会通知视图它的状态已经改变。
  
⑤ 视图向模型询问状态
  视图可以直接从模型取得它的显示状态。视图做这个动作一般有两个因素:一是在模型通知视图它的状态改变;二是控制器请求视图改变。

示例

这里写图片描述

  如上图所示,两个对话框是由View创建出来的。Control View 可以控制Display View中显示的内容,点击“Start”按钮后可以在Control View中输入数值,点击“Set”按钮便可以设置到Display View中。若点击“Stop”按钮后,无法再设置值到Display View中。“Increase”按钮可以让Display View中的数值加一,“Decrease”可以让Display View中的数值减一。类图如下所示:

这里写图片描述

Model:实现了可观察者接口,下面的方法允许观察者注册或者删除自己。

void registerObserver(IObserver* observer);void removeObserver(IObserver* observer);

另开放下面的接口供Controller可以改变Model的状态:

void initialize();void on();void off();void setValue(int value);

开放下面的接口供View可以获取Model的状态:

int getValue();

View:为了强调包含模型的视图的界面和包含其他用户控制的界面的差异,将界面设计成两个窗口(其实是一个类)。
  View同时包含了IModel和IController的指针,但两者的作用完全不同,如下所示:

IModel* m_model;            // 包含模型的指针作用:1.向模型注册观察者 2.从模型获取数据IController* m_controller;  // 控制器为视图的策略(所有用户操作交给控制器处理)

  View同样开放一些接口,供Controller来改变View的状态:

void enableStartBtn();void disableStartBtn();void enableStopBtn();void disableStopBtn();

  View为模型的观察者,必须实现观察者接口,以便在Model状态改变时通知View:

void updateValue();

  
  View在用户操作界面是会调用Controller如下所示的接口:

void start();void stop();void increaseValue();void decreaseValue();void setValue(int value);

控制器:Controller是策略,把它插进View中,让View变得聪明。控制器是连接View和Model的中间部件,View将用户的操作传给Controller,Controller ”解读“之后再传给Model。

  Controller是通过View的构造函数传入View的。为了Controller能够改变View的状态,在Controller注册为View的策略的时候,View必须将自己的指针设置给Controller,如下所示:

View::View(IController* controller, IModel* model, QWidget *parent) : QWidget(parent){    this->m_controller = controller;    // 控制器作为视图的策略,让视图变得聪明    m_controller->setView(this);        // 把View的指针设置到控制器,用于控制器改变视图的状态    // 其他操作}

下面列出全部代码(本示例是基于Qt5.6开发的):

IObserver.h

#ifndef IOSERVER_H#define IOSERVER_H// 观察者接口class IObserver{public:    IObserver() {}    virtual ~IObserver() {}    virtual void updateValue() = 0;};#endif

Model.h

#ifndef MODEL_H#define MODEL_H#include "IObserver.h"#include <QList>// 模型接口class IModel{public:    IModel() {}    virtual ~IModel() {}    virtual void initialize() = 0;    virtual void on() = 0;      // 开始显示    virtual void off() = 0;     // 停止显示    virtual void setValue(int value) = 0;    virtual int getValue() = 0;    virtual void registerObserver(IObserver* observer) = 0;     // 注册观察者    virtual void removeObserver(IObserver* observer) = 0;       // 删除观察者    virtual void notify() = 0;  // 通知观察者};class Model : public IModel{private:    QList<IObserver*> m_observers;    int m_value;public:    Model();    void initialize();    void on();    void off();    void setValue(int value);    int getValue();    void registerObserver(IObserver* observer);    void removeObserver(IObserver* observer);    void notify();};#endif // MODEL_H

Model.cpp

#include "Model.h"#include "View.h"Model::Model(){    m_value = 0;}void Model::initialize(){}void Model::on(){    setValue(90);}void Model::off(){    setValue(0);}void Model::setValue(int value){    this->m_value = value;    notify();}int Model::getValue(){    return m_value;}void Model::registerObserver(IObserver* observer){    m_observers.append(observer);}void Model::removeObserver(IObserver* observer){    m_observers.removeOne(observer);}void Model::notify(){    for (int i=0; i<m_observers.size(); i++) {        m_observers[i]->updateValue();    }}

View.h

#ifndef VIEW_H#define VIEW_H#include "IObserver.h"#include <QWidget>#include <QLineEdit>#include <QPushButton>#include <QDialog>#include <QLabel>class IModel;class IController;class View : public QWidget, public IObserver{    Q_OBJECTprivate:    IModel* m_model;            // 包含模型的指针作用:1.向模型注册观察者 2.从模型获取数据    IController* m_controller;  // 控制器为视图的策略(所有用户操作交给控制器处理)private:    QLineEdit* inputEdit;    QPushButton* startBtn;    QPushButton* stopBtn;    QDialog* displayDialog;    QLabel* displayLabel;    void constructUI();protected:    void closeEvent(QCloseEvent *event);public:    View(IController* controller, IModel* model, QWidget *parent = 0);    ~View();    void enableStartBtn();    void disableStartBtn();    void enableStopBtn();    void disableStopBtn();    void updateValue();protected slots:    void onSetBtn();    void onStartBtn();    void onStopBtn();    void onIncreaseBtn();    void onDecreaseBtn();};#endif // VIEW_H

View.cpp

#include "View.h"#include "Model.h"#include "Controller.h"#include <QGridLayout>View::View(IController* controller, IModel* model, QWidget *parent)    : QWidget(parent){    this->m_controller = controller;    // 控制器作为视图的策略,让视图变得聪明    this->m_model = model;    m_model->registerObserver(this);    // 向模型注册自己为观察者    m_controller->setView(this);        // 把View的指针设置到控制器,用于控制器改变视图的状态    constructUI();    disableStopBtn();    enableStartBtn();}View::~View(){}void View::updateValue(){    int value = m_model->getValue();    if (0 == value) {        displayLabel->setText("Offline");    } else {        displayLabel->setText("Current value: " + QString::number(value));    }}void View::constructUI(){    this->resize(300, 200);    inputEdit = new QLineEdit();    QPushButton* setBtn = new QPushButton();    setBtn->setText("Set");    connect(setBtn, SIGNAL(clicked()), this, SLOT(onSetBtn()));    startBtn = new QPushButton();    startBtn->setText("Start");    connect(startBtn, SIGNAL(clicked()), this, SLOT(onStartBtn()));    stopBtn = new QPushButton();    stopBtn->setText("Stop");    connect(stopBtn, SIGNAL(clicked()), this, SLOT(onStopBtn()));    QPushButton* increaseBtn = new QPushButton();    increaseBtn->setText("Increase");    connect(increaseBtn, SIGNAL(clicked()), this, SLOT(onIncreaseBtn()));    QPushButton* decreaseBtn = new QPushButton();    decreaseBtn->setText("Decrease");    connect(decreaseBtn, SIGNAL(clicked()), this, SLOT(onDecreaseBtn()));    QGridLayout* mainLayout = new QGridLayout(this);    mainLayout->addWidget(inputEdit, 0, 0, 1, 3);    mainLayout->addWidget(setBtn, 0, 3);    mainLayout->addWidget(startBtn, 1, 0);    mainLayout->addWidget(stopBtn, 1, 1);    mainLayout->addWidget(increaseBtn, 1, 2);    mainLayout->addWidget(decreaseBtn, 1, 3);    this->setWindowTitle("Control View");    this->resize(350, 70);    this->show();    displayDialog = new QDialog();    displayLabel = new QLabel(displayDialog);    displayDialog->setWindowTitle("Display View");    displayDialog->resize(200, 50);    displayLabel->resize(150, 20);    displayLabel->move(10, 10);    displayDialog->show();}void View::enableStartBtn(){    startBtn->setEnabled(true);}void View::disableStartBtn(){    startBtn->setEnabled(false);}void View::enableStopBtn(){    stopBtn->setEnabled(true);}void View::disableStopBtn(){    stopBtn->setEnabled(false);}void View::onSetBtn(){    QString string = inputEdit->text();    if (string.isEmpty()) {        return;    }    int value = string.toInt();    m_controller->setValue(value);}void View::onStartBtn(){    m_controller->start();}void View::onStopBtn(){     m_controller->stop();}void View::onIncreaseBtn(){     m_controller->increaseValue();}void View::onDecreaseBtn(){     m_controller->decreaseValue();}void View::closeEvent(QCloseEvent *){    displayDialog->close();    delete displayDialog;}

Controller.h

#ifndef CONTROLLER_H#define CONTROLLER_H#include "Model.h"#include "View.h"class IController{public:    IController() {}    virtual ~IController() {}    virtual void start() = 0;    virtual void stop() = 0;    virtual void increaseValue() = 0;    virtual void decreaseValue() = 0;    virtual void setValue(int value) = 0;    virtual void setView(View* view) = 0;};class Controller : public IController{private:    IModel* m_model;    View* m_view;public:    Controller(IModel* model);    void start();    void stop();    void increaseValue();    void decreaseValue();    void setValue(int value);    void setView(View* view);};#endif // CONTROLLER_H

Controller.cpp

#include "Controller.h"Controller::Controller(IModel *model){    this->m_model = model;}void Controller::start(){    m_model->on();    m_view->disableStartBtn();    m_view->enableStopBtn();}void Controller::stop(){    m_model->off();    m_view->enableStartBtn();    m_view->disableStopBtn();}void Controller::increaseValue(){    int value = m_model->getValue();    m_model->setValue(value+1);}void Controller::decreaseValue(){    int value = m_model->getValue();    m_model->setValue(value-1);}void Controller::setValue(int value){    m_model->setValue(value);}void Controller::setView(View* view){    m_view = view;}

main.cpp

#include "View.h"#include "Model.h"#include "Controller.h"#include <QApplication>int main(int argc, char *argv[]){    QApplication a(argc, argv);    IModel* model = new Model();    IController* controller = new Controller(model);    View* view = new View(controller, model);    return a.exec();}

MVC.pro

QT       += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = MVCTEMPLATE = appSOURCES += main.cpp\        View.cpp \    Controller.cpp \    Model.cppHEADERS  += View.h \    Controller.h \    Model.h \    IObserver.h

测试

如下为测试结果:
这里写图片描述

原创粉丝点击