理解MVC我们从下面的一个小例子开始。
1. 需求
实现一个加法计算器,如下图:


2. 最简单的实现方法
2.1 实现方法
将界面和逻辑写在一起
2.2 出现的问题
- 逻辑相对稳定,界面却多变。
 - 修改界面代码,将不得不修改逻辑代码(如下面的代码),可能会引入bug,增加测试工作。
 - 代码不优雅。一旦项目变得复杂,代码将很乱,难以维护。
 
2.3 代码(界面1)

- view.h
 
            
            
              c++
              
              
            
          
          #ifndef VIEW_H
#define VIEW_H
#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLineEdit>
class View : public QWidget
{
    Q_OBJECT
public:
    View(QWidget *parent = nullptr);
    ~View();
private:
    QVBoxLayout *m_layout;
    QLineEdit *m_valueEdit_1;
    QLineEdit *m_valueEdit_2;
    QLineEdit *m_sumEdit;
    QPushButton *m_addBtn;
private slots:
    void slot_addBtn(bool);
};
#endif // VIEW_H
        - view.cpp
 
            
            
              c++
              
              
            
          
          #include "view.h"
View::View(QWidget *parent)
    : QWidget(parent)
{
    //ui
    m_layout = new QVBoxLayout(this);
    m_valueEdit_1 = new QLineEdit();
    m_valueEdit_2 = new QLineEdit();
    m_sumEdit = new QLineEdit();
    m_addBtn = new QPushButton("Add");
    m_layout->addWidget(m_valueEdit_1);
    m_layout->addWidget(m_valueEdit_2);
    m_layout->addWidget(m_sumEdit);
    m_layout->addWidget(m_addBtn);
    this->resize(300, 200);
    //逻辑
    connect(m_addBtn, SIGNAL(clicked(bool)), this, SLOT(slot_addBtn(bool)));
}
View::~View()
{
}
void View::slot_addBtn(bool)
{
    int v1 = m_valueEdit_1->text().toInt();
    int v2 = m_valueEdit_2->text().toInt();
    QString sum = QString::number(v1 + v2);
    m_sumEdit->setText(sum);
}
        - main.cpp
 
            
            
              c++
              
              
            
          
          #include "view.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    View w;
    w.show();
    return a.exec();
}
        2.4 代码(界面2)

- view.h
 
            
            
              cpp
              
              
            
          
          #ifndef VIEW_H
#define VIEW_H
#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QSlider>
class View : public QWidget
{
    Q_OBJECT
public:
    View(QWidget *parent = nullptr);
    ~View();
private:
    QVBoxLayout *m_layout;
    QSlider *m_valueSlider_1;
    QSlider *m_valueSlider_2;
    QSlider *m_sumSlider;
    QPushButton *m_addBtn;
private slots:
    void slot_addBtn(bool);
};
#endif // VIEW_H
        - view.cpp
 
            
            
              cpp
              
              
            
          
          #include "view.h"
View::View(QWidget *parent)
    : QWidget(parent)
{
    //ui
    m_layout = new QVBoxLayout(this);
    m_valueSlider_1 = new QSlider();
    m_valueSlider_2 = new QSlider();
    m_sumSlider = new QSlider();
    m_addBtn = new QPushButton("Add");
    m_valueSlider_1->setOrientation(Qt::Horizontal);
    m_valueSlider_2->setOrientation(Qt::Horizontal);
    m_sumSlider->setOrientation(Qt::Horizontal);
    m_layout->addWidget(m_valueSlider_1);
    m_layout->addWidget(m_valueSlider_2);
    m_layout->addWidget(m_sumSlider);
    m_layout->addWidget(m_addBtn);
    this->resize(300, 200);
    //逻辑
    connect(m_addBtn, SIGNAL(clicked(bool)), this, SLOT(slot_addBtn(bool)));
}
View::~View()
{
}
void View::slot_addBtn(bool)
{
    int v1 = m_valueSlider_1->value();
    int v2 = m_valueSlider_2->value();
    int sum = v1 + v2;
    m_sumSlider->setValue(sum);
}
        - main.cpp(未修改)
 
3. 改进方法(Model-View, MV)
3.1 改进目标
- 界面与逻辑分离,实现界面修改后逻辑代码一点都不动
 
3.2 实现方法
- 将
View和Model代码分离,逻辑代码放到model中, 界面代码放在view中。 
3.3 出现的问题
View依赖于Model。
3.4 代码(界面1)

- model.h
 
            
            
              cpp
              
              
            
          
          #ifndef MODEL_H
#define MODEL_H
#include <QObject>
class Model : public QObject
{
    Q_OBJECT
public:
    explicit Model(QObject *parent = nullptr);
public slots:
    void slot_addFun(int a, int b);
private:
    int m_sum;
signals:
    void sig_sumUpdate(int sum);
};
#endif // MODEL_H
        - model.cpp
 
            
            
              cpp
              
              
            
          
          #include "model.h"
Model::Model(QObject *parent)
    : QObject{parent}
{
}
void Model::slot_addFun(int a, int b)
{
    m_sum = a + b;
    emit sig_sumUpdate(m_sum);
}
        - view.h
 
            
            
              cpp
              
              
            
          
          #ifndef VIEW_H
#define VIEW_H
#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include "model.h"
class View : public QWidget
{
    Q_OBJECT
public:
    View(Model *model, QWidget *parent = nullptr);
    ~View();
private:
    QVBoxLayout *m_layout;
    QLineEdit *m_valueEdit_1;
    QLineEdit *m_valueEdit_2;
    QLineEdit *m_sumEdit;
    QPushButton *m_addBtn;
    Model *m_model;
private slots:
    void slot_addBtn(bool);
    void slot_sumUpdate(int sum);
signals:
    void sig_addFun(int a, int b);
};
#endif // VIEW_H
        - view.cpp
 
            
            
              cpp
              
              
            
          
          #include "view.h"
View::View(Model *model, QWidget *parent)
    : QWidget(parent), m_model(model)
{
    //ui
    m_layout = new QVBoxLayout(this);
    m_valueEdit_1 = new QLineEdit();
    m_valueEdit_2 = new QLineEdit();
    m_sumEdit = new QLineEdit();
    m_addBtn = new QPushButton("Add");
    m_layout->addWidget(m_valueEdit_1);
    m_layout->addWidget(m_valueEdit_2);
    m_layout->addWidget(m_sumEdit);
    m_layout->addWidget(m_addBtn);
    this->resize(300, 200);
    //逻辑连接
    connect(m_addBtn, SIGNAL(clicked(bool)), this, SLOT(slot_addBtn(bool)));
    connect(this, SIGNAL(sig_addFun(int,int)), m_model, SLOT(slot_addFun(int,int)));
    connect(m_model, SIGNAL(sig_sumUpdate(int)), this, SLOT(slot_sumUpdate(int)));
}
View::~View()
{
}
void View::slot_addBtn(bool)
{
    int v1 = m_valueEdit_1->text().toInt();
    int v2 = m_valueEdit_2->text().toInt();
    emit sig_addFun(v1, v2);
}
void View::slot_sumUpdate(int sum)
{
    m_sumEdit->setText(QString::number(sum));
}
        - main.cpp
 
            
            
              cpp
              
              
            
          
          #include "view.h"
#include "model.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Model* model = new Model();
    View* view = new View(model);
    view->show();
    return a.exec();
}
        3.5 代码(界面2)

- model.h(未修改)
 - model.cpp(未修改)
 - view.h
 
            
            
              cpp
              
              
            
          
          #ifndef VIEW_H
#define VIEW_H
#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QSlider>
#include "model.h"
class View : public QWidget
{
    Q_OBJECT
public:
    View(Model *model, QWidget *parent = nullptr);
    ~View();
private:
    QVBoxLayout *m_layout;
    QSlider *m_valueSlider_1;
    QSlider *m_valueSlider_2;
    QSlider *m_sumSlider;
    QPushButton *m_addBtn;
    Model *m_model;
private slots:
    void slot_addBtn(bool);
    void slot_sumUpdate(int sum);
signals:
    void sig_addFun(int a, int b);
};
#endif // VIEW_H
        - view.cpp
 
            
            
              cpp
              
              
            
          
          #include "view.h"
View::View(Model *model, QWidget *parent)
    : QWidget(parent), m_model(model)
{
    //ui
    m_layout = new QVBoxLayout(this);
    m_valueSlider_1 = new QSlider();
    m_valueSlider_2 = new QSlider();
    m_sumSlider = new QSlider();
    m_addBtn = new QPushButton("Add");
    m_valueSlider_1->setOrientation(Qt::Horizontal);
    m_valueSlider_2->setOrientation(Qt::Horizontal);
    m_sumSlider->setOrientation(Qt::Horizontal);
    m_layout->addWidget(m_valueSlider_1);
    m_layout->addWidget(m_valueSlider_2);
    m_layout->addWidget(m_sumSlider);
    m_layout->addWidget(m_addBtn);
    this->resize(300, 200);
    //逻辑连接
    connect(m_addBtn, SIGNAL(clicked(bool)), this, SLOT(slot_addBtn(bool)));
    connect(this, SIGNAL(sig_addFun(int,int)), m_model, SLOT(slot_addFun(int,int)));
    connect(m_model, SIGNAL(sig_sumUpdate(int)), this, SLOT(slot_sumUpdate(int)));
}
View::~View()
{
}
void View::slot_addBtn(bool)
{
    int v1 = m_valueSlider_1->value();
    int v2 = m_valueSlider_2->value();
    emit sig_addFun(v1, v2);
}
void View::slot_sumUpdate(int sum)
{
    m_sumSlider->setValue(sum);
}
        - main.cpp(未修改)
 
4. 继续改进(Model-View-Controller, MVC)
4.1 改进目标
- 将
Model与View彻底解耦,互相不知道对方的存在。 
4.2 实现方法
- 在
View与Model中间添加一个中介,即Controller. 
4.3 出现的新问题
- 至此就实现了
MVC - 出现的新问题就是
MVC的问题,例如:随着项目越来越复杂,Controller会变得冗长。 
4.4 代码(界面1)

- model.h
 
            
            
              cpp
              
              
            
          
          #ifndef MODEL_H
#define MODEL_H
#include <QObject>
class Model : public QObject
{
    Q_OBJECT
public:
    explicit Model(QObject *parent = nullptr);
public slots:
    void slot_addFun(int a, int b);
private:
    int m_sum;
signals:
    void sig_sumUpdate(int sum);
};
#endif // MODEL_H
        - model.cpp
 
            
            
              cpp
              
              
            
          
          #include "model.h"
Model::Model(QObject *parent)
    : QObject{parent}
{
}
void Model::slot_addFun(int a, int b)
{
    m_sum = a + b;
    emit sig_sumUpdate(m_sum);
}
        - view.h
 
            
            
              cpp
              
              
            
          
          #ifndef VIEW_H
#define VIEW_H
#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLineEdit>
class View : public QWidget
{
    Q_OBJECT
public:
    View(QWidget *parent = nullptr);
    ~View();
private:
    QVBoxLayout *m_layout;
    QLineEdit *m_valueEdit_1;
    QLineEdit *m_valueEdit_2;
    QLineEdit *m_sumEdit;
    QPushButton *m_addBtn;
private slots:
    void slot_addBtn(bool);
    void slot_sumUpdate(int sum);
signals:
    void sig_addFun(int a, int b);
};
#endif // VIEW_H
        - view.cpp
 
            
            
              cpp
              
              
            
          
          #include "view.h"
View::View(QWidget *parent)
    : QWidget(parent)
{
    //ui
    m_layout = new QVBoxLayout(this);
    m_valueEdit_1 = new QLineEdit();
    m_valueEdit_2 = new QLineEdit();
    m_sumEdit = new QLineEdit();
    m_addBtn = new QPushButton("Add");
    m_layout->addWidget(m_valueEdit_1);
    m_layout->addWidget(m_valueEdit_2);
    m_layout->addWidget(m_sumEdit);
    m_layout->addWidget(m_addBtn);
    this->resize(300, 200);
    //逻辑
    connect(m_addBtn, SIGNAL(clicked(bool)), this, SLOT(slot_addBtn(bool)));
}
View::~View()
{
}
void View::slot_addBtn(bool)
{
    int v1 = m_valueEdit_1->text().toInt();
    int v2 = m_valueEdit_2->text().toInt();
    emit sig_addFun(v1, v2);
}
void View::slot_sumUpdate(int sum)
{
    m_sumEdit->setText(QString::number(sum));
}
        - controller.h
 
            
            
              cpp
              
              
            
          
          #ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QObject>
#include "model.h"
#include "view.h"
class Controller : public QObject
{
    Q_OBJECT
public:
    explicit Controller(Model *model, View *view, QObject *parent = nullptr);
private:
    Model *m_model;
    View  *m_view;
signals:
};
#endif // CONTROLLER_H
        - controller.cpp
 
            
            
              cpp
              
              
            
          
          #include "controller.h"
Controller::Controller(Model *model, View *view, QObject *parent)
    : QObject{parent}, m_model(model), m_view(view)
{
    connect(m_view, SIGNAL(sig_addFun(int,int)), m_model, SLOT(slot_addFun(int,int)));
    connect(m_model, SIGNAL(sig_sumUpdate(int)), m_view, SLOT(slot_sumUpdate(int)));
}
        - main.cpp
 
            
            
              cpp
              
              
            
          
          #include "view.h"
#include "model.h"
#include <QApplication>
#include "model.h"
#include "view.h"
#include "controller.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Model* model = new Model();
    View* view = new View();
    Controller* controller = new Controller(model, view);
    view->show();
    return a.exec();
}
        4.5 代码(界面2)

- model.h(未修改)
 - model.cpp(未修改)
 - view.h
 
            
            
              cpp
              
              
            
          
          #ifndef VIEW_H
#define VIEW_H
#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QSlider>
class View : public QWidget
{
    Q_OBJECT
public:
    View(QWidget *parent = nullptr);
    ~View();
private:
    QVBoxLayout *m_layout;
    QSlider *m_valueSlider_1;
    QSlider *m_valueSlider_2;
    QSlider *m_sumSlider;
    QPushButton *m_addBtn;
private slots:
    void slot_addBtn(bool);
    void slot_sumUpdate(int sum);
signals:
    void sig_addFun(int a, int b);
};
#endif // VIEW_H
        - view.cpp
 
            
            
              cpp
              
              
            
          
          #include "view.h"
View::View(QWidget *parent)
    : QWidget(parent)
{
    //ui
    m_layout = new QVBoxLayout(this);
    m_valueSlider_1 = new QSlider();
    m_valueSlider_2 = new QSlider();
    m_sumSlider = new QSlider();
    m_addBtn = new QPushButton("Add");
    m_valueSlider_1->setOrientation(Qt::Horizontal);
    m_valueSlider_2->setOrientation(Qt::Horizontal);
    m_sumSlider->setOrientation(Qt::Horizontal);
    m_layout->addWidget(m_valueSlider_1);
    m_layout->addWidget(m_valueSlider_2);
    m_layout->addWidget(m_sumSlider);
    m_layout->addWidget(m_addBtn);
    this->resize(300, 200);
    //逻辑
    connect(m_addBtn, SIGNAL(clicked(bool)), this, SLOT(slot_addBtn(bool)));
}
View::~View()
{
}
void View::slot_addBtn(bool)
{
    int v1 = m_valueSlider_1->value();
    int v2 = m_valueSlider_2->value();
    emit sig_addFun(v1, v2);
}
void View::slot_sumUpdate(int sum)
{
    m_sumSlider->setValue(sum);
}
        - controller.h(未修改)
 - controller.cpp(未修改)
 - main.cpp(未修改)
 
5. 对MVC和MVP的理解
5.1 MVC
- 网上对
MVC的解释有很多,比较混乱 - 我下面是我比较认可的一种:
Controller作为View和Model之间的中介传递信息View与Model彻底解耦Model开发者与View开发者可以互相独立开发
 

5.2 MVP
MVP的概念更混乱。- 维基百科上解释
MVP是MVC的改进。 - 暂且将MVP理解为一种特殊的
MCV吧。 
参考
# 浅谈 MVC、MVP 和 MVVM 架构模式\]([浅谈 MVC、MVP 和 MVVM 架构模式 - 面向信仰编程](https://link.juejin.cn?target=https%3A%2F%2Fdraven.co%2Fmvx%2F "https://draven.co/mvx/"))