当前位置: 首页 > news >正文

MVVM设计模式

‌MVVM(Model-View-ViewModel)是一种软件设计模式,MVVM模式由三个主要部分组成:

‌Model(模型)‌:负责管理应用程序的业务逻辑和数据。它不关心UI如何展示数据,主要负责与服务器通信和数据处处理‌。
‌View(视图)‌:直接与用户交互的界面,负责展示数据。视图不包含业务逻辑,只负责数据的展示‌。
‌ViewModel(视图模型)‌:作为视图和模型之间的桥梁,包含UI逻辑,通过数据绑定机制驱动视图的变化。它处理用户的输入并将结果传递给模型‌。

MVVM的核心机制和优势
‌数据绑定‌是MVVM的核心机制,它允许视图和视图模型之间的自动同步,无需手动编写繁琐的代码来更新界面‌。
这种设计模式的主要优势包括:
‌解耦‌:视图和模型完全解耦,视图模型管理两者的交互,提高了代码的可维护性和扩展性‌。
‌可测试性‌:由于视图模型不依赖于视图,可以通过单元测试来验证业务逻辑的正确性,而不需要启动UI环境‌。
‌提高开发效率‌:通过数据绑定和事件处理,简化了开发过程,减少了手动同步数据的需要‌。

项目结构

mvvm_example/
├── main.cpp
├── view.h
├── view.cpp
├── viewmodel.h
├── viewmodel.cpp
├── model.h
└── model.cpp

代码实现
model.h

#ifndef MODEL_H
#define MODEL_H#include <QObject>
#include <QString>class Model : public QObject
{Q_OBJECTQ_PROPERTY(QString data READ data WRITE setData NOTIFY dataChanged)public:explicit Model(QObject *parent = nullptr);QString data() const;void setData(const QString &newData);signals:void dataChanged();private:QString m_data;
};#endif // MODEL_H

model.cpp

#include "model.h"Model::Model(QObject *parent) : QObject(parent)
{
}QString Model::data() const
{return m_data;
}void Model::setData(const QString &newData)
{if (m_data != newData) {m_data = newData;emit dataChanged();}
}

viewmodel.h

#ifndef VIEWMODEL_H
#define VIEWMODEL_H#include <QObject>
#include "model.h"class ViewModel : public QObject
{Q_OBJECTQ_PROPERTY(QString displayData READ displayData NOTIFY displayDataChanged)public:explicit ViewModel(Model *model, QObject *parent = nullptr);QString displayData() const;signals:void displayDataChanged();public slots:void onModelDataChanged();void setViewModelData(const QString &newData);private:Model *m_model;
};#endif // VIEWMODEL_H

viewmodel.cpp

#include "viewmodel.h"ViewModel::ViewModel(Model *model, QObject *parent) : QObject(parent), m_model(model)
{connect(m_model, &Model::dataChanged, this, &ViewModel::onModelDataChanged);
}QString ViewModel::displayData() const
{return m_model->data();
}void ViewModel::onModelDataChanged()
{emit displayDataChanged();
}void ViewModel::setViewModelData(const QString &newData)
{m_model->setData(newData);
}

view.h

#ifndef VIEW_H
#define VIEW_H#include <QWidget>
#include "viewmodel.h"QT_BEGIN_NAMESPACE
namespace Ui { class View; }
QT_END_NAMESPACEclass View : public QWidget
{Q_OBJECTpublic:explicit View(ViewModel *viewModel, QWidget *parent = nullptr);~View();private slots:void on_pushButton_clicked();void updateLabel(const QString &data);private:Ui::View *ui;ViewModel *m_viewModel;
};
#endif // VIEW_H

view.cpp

#include "view.h"
#include "ui_view.h"View::View(ViewModel *viewModel, QWidget *parent): QWidget(parent), ui(new Ui::View), m_viewModel(viewModel)
{ui->setupUi(this);// 绑定 ViewModel 的 displayDataChanged 信号到更新标签的槽函数connect(m_viewModel, &ViewModel::displayDataChanged, this, [this]() {updateLabel(m_viewModel->displayData());});// 绑定按钮点击信号到槽函数connect(ui->pushButton, &QPushButton::clicked, this, &View::on_pushButton_clicked);
}View::~View()
{delete ui;
}void View::on_pushButton_clicked()
{QString input = ui->lineEdit->text();m_viewModel->setViewModelData(input);
}void View::updateLabel(const QString &data)
{ui->label->setText(data);
}

main.cpp

#include "view.h"
#include "model.h"
#include "viewmodel.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Model model;ViewModel viewModel(&model);View view(&viewModel);view.show();return a.exec();
}

在上述代码里,MainWindow 类实际上就充当了 View 的角色。不过为了更清晰地体现 View 的概念,我们可以把界面相关的操作进一步封装,并且更明确地展示 ViewViewModelModel 之间的交互。以下是改进后的代码:

项目结构

mvvm_example/
├── main.cpp
├── view.h
├── view.cpp
├── viewmodel.h
├── viewmodel.cpp
├── model.h
└── model.cpp

代码实现

model.h
#ifndef MODEL_H
#define MODEL_H#include <QObject>
#include <QString>class Model : public QObject
{Q_OBJECTQ_PROPERTY(QString data READ data WRITE setData NOTIFY dataChanged)public:explicit Model(QObject *parent = nullptr);QString data() const;void setData(const QString &newData);signals:void dataChanged();private:QString m_data;
};#endif // MODEL_H
model.cpp
#include "model.h"Model::Model(QObject *parent) : QObject(parent)
{
}QString Model::data() const
{return m_data;
}void Model::setData(const QString &newData)
{if (m_data != newData) {m_data = newData;emit dataChanged();}
}
viewmodel.h
#ifndef VIEWMODEL_H
#define VIEWMODEL_H#include <QObject>
#include "model.h"class ViewModel : public QObject
{Q_OBJECTQ_PROPERTY(QString displayData READ displayData NOTIFY displayDataChanged)public:explicit ViewModel(Model *model, QObject *parent = nullptr);QString displayData() const;signals:void displayDataChanged();public slots:void onModelDataChanged();void setViewModelData(const QString &newData);private:Model *m_model;
};#endif // VIEWMODEL_H
viewmodel.cpp
#include "viewmodel.h"ViewModel::ViewModel(Model *model, QObject *parent) : QObject(parent), m_model(model)
{connect(m_model, &Model::dataChanged, this, &ViewModel::onModelDataChanged);
}QString ViewModel::displayData() const
{return m_model->data();
}void ViewModel::onModelDataChanged()
{emit displayDataChanged();
}void ViewModel::setViewModelData(const QString &newData)
{m_model->setData(newData);
}
view.h
#ifndef VIEW_H
#define VIEW_H#include <QWidget>
#include "viewmodel.h"QT_BEGIN_NAMESPACE
namespace Ui { class View; }
QT_END_NAMESPACEclass View : public QWidget
{Q_OBJECTpublic:explicit View(ViewModel *viewModel, QWidget *parent = nullptr);~View();private slots:void on_pushButton_clicked();void updateLabel(const QString &data);private:Ui::View *ui;ViewModel *m_viewModel;
};
#endif // VIEW_H
view.cpp
#include "view.h"
#include "ui_view.h"View::View(ViewModel *viewModel, QWidget *parent): QWidget(parent), ui(new Ui::View), m_viewModel(viewModel)
{ui->setupUi(this);// 绑定 ViewModel 的 displayDataChanged 信号到更新标签的槽函数connect(m_viewModel, &ViewModel::displayDataChanged, this, [this]() {updateLabel(m_viewModel->displayData());});// 绑定按钮点击信号到槽函数connect(ui->pushButton, &QPushButton::clicked, this, &View::on_pushButton_clicked);
}View::~View()
{delete ui;
}void View::on_pushButton_clicked()
{QString input = ui->lineEdit->text();m_viewModel->setViewModelData(input);
}void View::updateLabel(const QString &data)
{ui->label->setText(data);
}
main.cpp
#include "view.h"
#include "model.h"
#include "viewmodel.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Model model;ViewModel viewModel(&model);View view(&viewModel);view.show();return a.exec();
}

代码解释

View
  • 构造函数:接收一个 ViewModel 对象的指针,负责初始化界面并建立信号与槽的连接。
  • on_pushButton_clicked 槽函数:当用户点击按钮时,获取输入框中的文本,然后调用 ViewModelsetViewModelData 方法更新数据。
  • updateLabel 槽函数:当 ViewModeldisplayData 发生变化时,更新界面上的标签文本。
ViewModel
  • 作为 ViewModel 之间的桥梁,负责处理业务逻辑和数据转换。当 Model 的数据发生变化时,会发出 displayDataChanged 信号通知 View 更新。
Model
  • 负责存储和管理数据,当数据发生变化时发出 dataChanged 信号。
main.cpp
  • 创建 ModelViewModelView 对象,并显示 View

通过这种方式,我们清晰地划分了 ViewViewModelModel 的职责,实现了 MVVM 模式。

http://www.lryc.cn/news/535145.html

相关文章:

  • 解决:Cannot find a valid baseurl for repo: base/7/x86_64
  • ffmpeg -codecs
  • 社区版IDEA中配置TomCat(详细版)
  • 强化学习 DPO 算法:基于人类偏好,颠覆 PPO 传统策略
  • 长安链支撑全国不动产登记数据可信流通
  • GitCode 助力 Dora SSR:开启游戏开发新征程
  • 获取 Windows 视频时长的正确方式——Windows Shell API 深度解析
  • Linux系统安装Nginx详解(适用于CentOS 7)
  • 深入理解Java对接DeepSeek
  • flutter isolate到底是啥
  • 深入剖析 Apache Shiro550 反序列化漏洞及复现
  • 计算机毕业设计——Springboot的简历系统
  • 【kubernetes组件合集】深入解析Kubernetes组件之三:client-go
  • 线程池-抢票系统性能优化
  • WebSocket 握手过程
  • VMware 虚拟机 ubuntu 20.04 扩容工作硬盘
  • 备战蓝桥杯:二分算法之牛可乐和魔法封印问题
  • 普通用户授权docker使用权限
  • 【实战篇】DeepSeek + ElevenLabs:让人工智能“开口说话”,打造你的专属语音助手!
  • Vision Transformer:打破CNN垄断,全局注意力机制重塑计算机视觉范式
  • LabVIEW国内外开发的区别
  • 【并发控制、更新、版本控制】.NET开源ORM框架 SqlSugar 系列
  • 淘宝App交易链路终端混合场景体验探索
  • 数据中心网络监控
  • 【含开题报告+文档+PPT+源码】基于springboot的汽车销售管理系统的设计与实现
  • flink cdc2.2.1同步postgresql表
  • rebase和merge
  • Spring boot中实现字典管理
  • 调用DeepSeek官方的API接口
  • 3.3 学习UVM中的uvm_driver 类分为几步?