前言

在之前的开发中,对于业务的解耦都是单独抽取出一个类,并且大量的业务逻辑写在ui类中,在学习了MVP架构模式后,尝试实现通过MVP(Model-View-Presenter)架构模式与抽象DAO(Data Access Object)层的结合,编写一个示例项目进行学习,具体的学习项目已上传git,地址:https://gitee.com/zbylalalala1/mvp_-study-demo.git。

一、MVP架构模式简介

MVP架构将应用程序分为三个核心组件:

  • Model :负责业务逻辑和数据管理
  • View :负责用户界面的展示和用户交互
  • Presenter :作为Model和View之间的桥梁,处理业务逻辑并协调两者之间的通信

    相比传统的MVC模式,MVP模式中的View更加被动,所有的业务逻辑都由Presenter处理,这使得单元测试变得更加容易。

二、整体架构设计

系统在传统MVP基础上增加了抽象DAO层,形成了如下的分层架构:

┌─────────────────┐
│      View       │ 用户界面层
├─────────────────┤
│   Presenter     │ 业务逻辑层
├─────────────────┤
│     Model       │ 业务模型层
├─────────────────┤
│  IDeviceDAO     │ 数据访问抽象层
├─────────────────┤
│ SqliteDeviceDAO │ 具体实现层
├─────────────────┤
│DatabaseManager  │ 数据库管理层
└─────────────────┘

三、核心架构组件分析

3.1 抽象DAO层设计

抽象DAO层通过接口隔离了具体的数据访问实现:

// 抽象设备DAO接口
class IDeviceDAO : public QObject {
    Q_OBJECT public:
    virtual ~IDeviceDAO() = default;
    
    // 基本CRUD操作
    virtual bool addDevice(const Device& 
    device) = 0;
    virtual bool updateDevice(const Device& 
    device) = 0;
    virtual bool deleteDevice(int id) = 0;
    virtual Device getDeviceById(int id) = 0;
    
    // 查询操作
    virtual QList<Device> getAllDevices() = 0;
    virtual QList<Device> searchDevices(const 
    QString& searchText) = 0;
    virtual QList<Device> getDevicesByPage
    (int page, int pageSize, const QString& 
    filter = "") = 0;
    
    // 统计操作
    virtual int getTotalCount(const QString& 
    filter = "") = 0;
    
    // 初始化数据
    virtual bool insertTestData() = 0;
    virtual bool hasData() = 0;
    
signals:
    void errorOccurred(const QString &error);
}; // SQLite具体实现类
class SqliteDeviceDAO : public IDeviceDAO {
    Q_OBJECT
public:
    explicit SqliteDeviceDAO(QObject *parent 
    = nullptr);
    
    // 实现接口方法...
    
private:
    DatabaseManager* m_dbManager;
    Device queryToDevice(const QSqlQuery& 
    query);
};

3.2 Model层设计

Model层通过依赖倒置原则,依赖于抽象的IDeviceDAO接口而非具体实现:

class DeviceModel : public QObject {
    Q_OBJECT public:
    explicit DeviceModel(QObject *parent = 
    nullptr);
    ~DeviceModel();
    
    bool initialize();
    QSqlQueryModel* getTableModel();
    
    // 设备操作
    bool addDevice(const Device& device);
    bool updateDevice(const Device& device);
    bool deleteDevice(int id);
    
    // 搜索和过滤
    void searchDevices(const QString& 
    searchText);
    void resetFilter();
    
    // 分页控制
    void setPageSize(int pageSize);
    void setCurrentPage(int page);
    int getTotalPages() const;
    
signals:
    void dataChanged();
    void errorOccurred(const QString &error); private:
    IDeviceDAO* m_deviceDAO;  // 使用接口指针,
    实现依赖倒置
    DatabaseManager* m_dbManager;
    QSqlQueryModel* m_tableModel;
    
    int m_pageSize;
    int m_currentPage;
    int m_totalRecords;
    QString m_currentFilter;
    
    void refreshData();
    void updatePagination();
};

3.3 Presenter层设计

Presenter作为View和Model之间的协调者,实现了完全的事件驱动架构:

class DevicePresenter : public QObject {
    Q_OBJECT public:
    explicit DevicePresenter(QObject *parent 
    = nullptr);
    ~DevicePresenter();
    
    // 依赖注入接口
    void setModel(DeviceModel* model);
    void setView(DeviceView* view);
    void connectSignals();
    bool initialize(); private slots:
    // 处理View的信号
    void onSearchRequested(const QString& 
    searchText);
    void onAddDeviceRequested();
    void onEditDeviceRequested(int deviceId);
    void onDeleteDeviceRequested(int 
    deviceId);
    
    // 处理Model的信号
    void onModelDataChanged();
    void onModelErrorOccurred(const QString& 
    error); private:
    DeviceModel* m_model;
    DeviceView* m_view;
    bool m_initialized;
};

3.4 View层设计

View层通过信号-槽机制与Presenter通信,保持完全的被动性:

class DeviceView : public QWidget {
    Q_OBJECT public:
    explicit DeviceView(QWidget *parent = 
    nullptr);
    
    // 界面更新接口
    void setTableModel(QAbstractItemModel* 
    model);
    void updatePaginationInfo(int 
    currentPage, int totalPages, int 
    totalRecords, int pageSize);
    
    // 用户输入接口
    QString getSearchText() const;
    int getSelectedPageSize() const; signals:
    // 用户操作信号
    void searchRequested(const QString& 
    searchText);
    void addDeviceRequested();
    void editDeviceRequested(int deviceId);
    void deleteDeviceRequested(int deviceId);
    void pageChanged(int page);
    void pageSizeChanged(int pageSize); public slots:
    void showMessage(const QString& message);
    void showError(const QString& error);
};

四、依赖注入与生命周期管理

在main函数中,我们通过依赖注入的方式创建和管理各个组件:

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    // 创建Model
    DeviceModel* model = new DeviceModel(&
    app);
    
    // 初始化Model
    if (!model->initialize()) {
        QMessageBox::critical(nullptr, "错误
        ", "无法初始化设备管理系统!");
        return -1;
    }
    
    // 创建View
    DeviceView* view = new DeviceView();
    
    // 创建Presenter
    DevicePresenter* presenter = new 
    DevicePresenter(&app);
    
    // 依赖注入
    presenter->setModel(model);
    presenter->setView(view);
    presenter->connectSignals();
    
    // 初始化并启动
    if (!presenter->initialize()) {
        return -1;
    }
    
    view->show();
    return app.exec();
}

Qt中MVP架构与抽象DAO层的结合示例的更多相关文章

  1. MVP架构在xamarin android中的简单使用

    好几个月没写文章了,使用xamarin android也快接近两年,还有一个月职业生涯就到两个年了,从刚出来啥也不会了,到现在回头看这个项目,真jb操蛋(真辛苦了实施的人了,无数次吐槽怎么这么丑),怪 ...

  2. (转)淘淘商城系列——SSM框架整合之Dao层整合

    http://blog.csdn.net/yerenyuan_pku/article/details/72721093 一个项目中往往有三层即Dao层.Service层和Web层,看标题就知道了,本文 ...

  3. 02.MyBatis在DAO层开发使用的Mapper动态代理方式

    在实际开发中,Mybatis作用于DAO层,那么Service层该如何调用Mybatis Mybatis鼓励使用Mapper动态代理的方式 Mapper接口开发方法只需要程序员编写Mapper接口(相 ...

  4. 一个项目中说系统分为表现层、控制层、逻辑层、DAO层和最终数据库五层架构-转

    表现层就是看到的东西,比如你现在看到的当前页面控制层就将你的请求从页面传到后台代码逻辑层就是处理你的请求的代码DAO层就是将数据存到数据库中的代码数据库就是数据库了,存东西用的 ,DAO层就是将访问数 ...

  5. 转:Android开发中的MVP架构(最后链接资源不错)

    Android开发中的MVP架构 最近越来越多的人开始谈论架构.我周围的同事和工程师也是如此.尽管我还不是特别深入理解MVP和DDD,但是我们的新项目还是决定通过MVP来构建. 这篇文章是我通过研究和 ...

  6. 转: Android开发中的MVP架构详解(附加链接比较不错)

    转: http://www.codeceo.com/article/android-mvp-artch.html 最近越来越多的人开始谈论架构.我周围的同事和工程师也是如此.尽管我还不是特别深入理解M ...

  7. 设计模式笔记之二:Android开发中的MVP架构(转)

    写在前面,本博客来源于公众号文章:http://mp.weixin.qq.com/s?__biz=MzA3MDMyMjkzNg==&mid=402435540&idx=1&sn ...

  8. Android中的MVP架构分解和实现

    1.概述 传统的Android开发架构通常是MVC模式. Model:业务逻辑和实体模型 View:相应于布局文件 Controllor:相应于Activity 单独从逻辑看起来很好,与我们做Web开 ...

  9. Android中的MVP架构初探

    说来羞愧,MVP的架构模式已经在Android领域出现一两年了.可是到今天自己才開始Android领域中的MVP架构征程. 闲话不多说,開始吧. 一.架构演变概述 我记得我找第一份工作时,面试官问我& ...

  10. Android架构(一)MVP架构在Android中的实践

    Android架构(一)MVP架构在Android中的实践 https://www.300168.com/yidong/show-2790.html   核心提示:为什么要重视程序的架构设计 对程序进 ...

随机推荐

  1. spring的控制反转DI---基于注解实现

    首先在pom.xml里面导入依赖: <dependencies> <!--要使用spring需要添加4个包但是maven会把他的几个依赖包同时下好--> <depende ...

  2. HarmonyOS运动开发:打造便捷的静态快捷菜单

    鸿蒙核心技术##运动开发# 前言 在运动类应用中,用户往往需要快速访问常用功能,如查看成绩.赛事信息或开始运动.为了提升用户体验,鸿蒙(HarmonyOS)提供了静态快捷菜单功能,允许用户从桌面直接跳 ...

  3. Apache Hudi 在袋鼠云数据湖平台的设计与实践

    在大数据处理中,实时数据分析是一个重要的需求.随着数据量的不断增长,对于实时分析的挑战也在不断加大,传统的批处理方式已经不能满足实时数据处理的需求,需要一种更加高效的技术来解决这个问题.Apache ...

  4. ChunJun&OceanBase联合方案首次发布:构建一体化数据集成方案

    8月27日,ChunJun社区与OceanBase社区联合组织的开源线下Meetup成功举办,会上重磅发布了「OceanBase&ChunJun:构建一体化数据集成方案」. 这是OceanBa ...

  5. Java源码分析系列笔记-6.ReentrantLock

    目录 1. 是什么 1.1. synchronized vs ReentranLock 2. 实现原理 2.1. uml图 3. 公平锁 3.1. 如何使用 3.2. 原理分析 3.2.1. 构造方法 ...

  6. AGC021E ball Eat chamelemons

    E - Ball Eat Chameleons 设颜色序列中有\(R\)个红球,\(B\)个蓝球,且有\(B+R=k\) 然后分类讨论: \(R<B\) 无解 \(R>B\) 这时有一种合 ...

  7. UFT remove duplicate value

  8. matlab绘图中set函数的使用汇总

    Matlab 绘图中set函数使用汇总 % 设置标题字体大小,字型 set(get(gca,'title'),'FontSize',10,'FontName','宋体'); % 设置X坐标标题字体大小 ...

  9. 4G DTU

    4G DTU是一种可以将RS232/485采集的数据通过3G/4G发送到云端服务器进行数据交互的传输设备.实现串口设备的无线长距离数据传输,进而实现远程数据通信管理,主要应用在远程数据采集和远程控制项 ...

  10. vue_条件渲染、列表渲染

    条件渲染 <html lang="en"> <head> <meta charset="UTF-8"> <title& ...