【Qt】Qt中对MVC,MVP的理解

理解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 实现方法

  • ViewModel代码分离,逻辑代码放到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 改进目标

  • ModelView彻底解耦,互相不知道对方的存在。

4.2 实现方法

  • ViewModel中间添加一个中介,即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作为ViewModel之间的中介传递信息
    • ViewModel彻底解耦
    • Model开发者与View开发者可以互相独立开发

5.2 MVP

  • MVP的概念更混乱。
  • 维基百科上解释MVPMVC的改进。
  • 暂且将MVP理解为一种特殊的MCV吧。

参考

# 浅谈 MVC、MVP 和 MVVM 架构模式\]([浅谈 MVC、MVP 和 MVVM 架构模式 - 面向信仰编程](https://link.juejin.cn?target=https%3A%2F%2Fdraven.co%2Fmvx%2F "https://draven.co/mvx/"))

相关推荐
我是菜鸟0713号3 天前
Qt 中 OPC UA 通讯实战
开发语言·qt
JCBP_3 天前
QT(4)
开发语言·汇编·c++·qt·算法
lqjun08274 天前
Qt程序单独运行报错问题
开发语言·qt
酷飞飞4 天前
Qt Designer与事件处理
开发语言·qt·命令模式
mkhase4 天前
9.12-QT-基本登陆界面实现
java·jvm·qt
咕噜咕噜啦啦4 天前
Qt之快捷键、事件处理、自定义按键——完成记事本项目
开发语言·qt
Quz4 天前
QML Charts组件之折线图的鼠标交互
qt
眠りたいです4 天前
基于脚手架微服务的视频点播系统-数据管理与网络通信部分的预备工作
c++·qt·ui·微服务·云原生·架构·媒体
bikong74 天前
Qt/C++,windows多进程demo
c++·windows·qt