【Qt】 设计模式

在Qt应用程序开发中,结合数据库操作、通信、界面逻辑和显示等功能,以下是常用的设计模式及其典型应用场景:

一、MVC/MVVM(模型-视图-控制器/视图模型)

作用:分离数据(模型)、界面(视图)和业务逻辑(控制器/视图模型),提升可维护性。
Qt实现

  • MVC:Qt提供QAbstractItemModelQListView/QTableView等组件,支持数据与视图分离。
  • MVVM:结合Qt的属性系统和信号槽,通过QObjectQ_PROPERTY实现视图模型。

典型场景

  • 数据库查询结果的表格展示(如QSqlTableModelQTableView结合)。
  • 表单数据的双向绑定(视图变化自动更新模型,反之亦然)。

示例代码

// 模型(数据库操作)
QSqlTableModel model;
model.setTable("users");
model.select();

// 视图(界面显示)
QTableView tableView;
tableView.setModel(model);

// 控制器(业务逻辑,如按钮点击事件)
QPushButton deleteButton("删除选中行");
connect(&deleteButton, &QPushButton::clicked, [&]() {
    QModelIndexList selected = tableView.selectedIndexes();
    if (!selected.isEmpty()) {
        model.removeRow(selected.first().row());
        model.submitAll();  // 提交到数据库
    }
});

二、单例模式(Singleton)

作用:确保一个类只有一个实例,并提供全局访问点。
典型场景

  • 数据库连接管理(避免重复创建连接)。
  • 全局配置管理器。
  • 网络通信模块(如唯一的WebSocket客户端)。

示例代码

class DatabaseManager {
public:
    static DatabaseManager& getInstance() {
        static DatabaseManager instance;  // 线程安全的单例实现
        return instance;
    }
    
    QSqlDatabase getDatabase() {
        return db;
    }
    
private:
    DatabaseManager() {
        db = QSqlDatabase::addDatabase("QSQLITE");
        db.setDatabaseName("mydatabase.db");
        if (!db.open()) {
            qDebug() << "Database error:" << db.lastError().text();
        }
    }
    
    ~DatabaseManager() {
        if (db.isOpen()) {
            db.close();
        }
    }
    
    QSqlDatabase db;
    Q_DISABLE_COPY(DatabaseManager)  // 禁止拷贝构造和赋值
};

三、观察者模式(Observer)

作用:对象间的一对多依赖关系,当一个对象状态变化时,所有依赖者自动收到通知。
Qt实现:基于信号槽机制。
典型场景

  • 数据库数据更新时通知界面刷新。
  • 网络通信中接收到新消息时通知相关模块。
  • 多窗口间的数据同步。

示例代码

// 数据模型(被观察对象)
class DataModel : public QObject {
    Q_OBJECT
public:
    void updateData(const QString& newData) {
        m_data = newData;
        emit dataChanged(m_data);  // 发送信号通知观察者
    }
    
signals:
    void dataChanged(const QString& data);
    
private:
    QString m_data;
};

// 视图(观察者)
class DataView : public QLabel {
    Q_OBJECT
public:
    explicit DataView(QWidget* parent = nullptr) : QLabel(parent) {
        connect(&model, &DataModel::dataChanged, this, &DataView::updateDisplay);
    }
    
private slots:
    void updateDisplay(const QString& data) {
        setText(data);  // 更新界面显示
    }
    
private:
    DataModel model;
};

四、工厂模式(Factory)

作用:通过工厂类创建对象,解耦对象的创建和使用。
典型场景

  • 根据配置动态创建不同类型的数据库连接(如MySQL、SQLite)。
  • 网络通信协议的抽象(如HTTP、WebSocket、MQTT)。

示例代码

// 抽象产品:数据库连接
class DatabaseConnection {
public:
    virtual bool open() = 0;
    virtual void close() = 0;
    virtual ~DatabaseConnection() {}
};

// 具体产品:MySQL连接
class MySQLConnection : public DatabaseConnection {
public:
    bool open() override { /* 实现MySQL连接逻辑 */ }
    void close() override { /* 实现MySQL关闭逻辑 */ }
};

// 具体产品:SQLite连接
class SQLiteConnection : public DatabaseConnection {
public:
    bool open() override { /* 实现SQLite连接逻辑 */ }
    void close() override { /* 实现SQLite关闭逻辑 */ }
};

// 工厂类
class DatabaseFactory {
public:
    static DatabaseConnection* createConnection(const QString& type) {
        if (type == "mysql") {
            return new MySQLConnection();
        } else if (type == "sqlite") {
            return new SQLiteConnection();
        }
        return nullptr;
    }
};

五、命令模式(Command)

作用:将请求封装为对象,支持请求的参数化、排队、记录和撤销。
典型场景

  • 数据库操作的批量执行(如事务中的多个增删改查)。
  • 撤销/重做功能的实现。

示例代码

// 抽象命令
class Command {
public:
    virtual void execute() = 0;
    virtual void undo() = 0;
    virtual ~Command() {}
};

// 具体命令:数据库插入
class InsertCommand : public Command {
public:
    InsertCommand(QSqlDatabase& db, const QString& table, const QVariantMap& data)
        : m_db(db), m_table(table), m_data(data) {}
    
    void execute() override {
        // 执行插入操作
        QSqlQuery query(m_db);
        QString fields = m_data.keys().join(", ");
        QString placeholders = QStringList(m_data.size(), "?").join(", ");
        query.prepare(QString("INSERT INTO %1 (%2) VALUES (%3)").arg(m_table, fields, placeholders));
        
        int i = 0;
        for (const auto& value : m_data.values()) {
            query.bindValue(i++, value);
        }
        
        m_success = query.exec();
        m_lastInsertId = query.lastInsertId();
    }
    
    void undo() override {
        // 撤销插入(删除刚插入的记录)
        if (m_success && m_lastInsertId.isValid()) {
            QSqlQuery query(m_db);
            query.prepare(QString("DELETE FROM %1 WHERE id = ?").arg(m_table));
            query.bindValue(0, m_lastInsertId);
            query.exec();
        }
    }
    
private:
    QSqlDatabase& m_db;
    QString m_table;
    QVariantMap m_data;
    bool m_success = false;
    QVariant m_lastInsertId;
};

六、状态模式(State)

作用:允许对象在内部状态改变时改变其行为,将状态逻辑封装到不同的状态类中。
典型场景

  • 网络连接状态管理(如未连接、连接中、已连接、断开)。
  • 数据库操作的状态流转(如事务的开始、提交、回滚)。

示例代码

// 抽象状态
class ConnectionState {
public:
    virtual void connect() = 0;
    virtual void disconnect() = 0;
    virtual void sendData(const QByteArray& data) = 0;
    virtual ~ConnectionState() {}
};

// 具体状态:未连接
class DisconnectedState : public ConnectionState {
public:
    void connect() override {
        // 执行连接逻辑
        qDebug() << "Connecting...";
        // 连接成功后切换到ConnectedState
    }
    
    void disconnect() override {
        qDebug() << "Already disconnected";
    }
    
    void sendData(const QByteArray& data) override {
        qDebug() << "Cannot send data: not connected";
    }
};

// 上下文类
class NetworkConnection {
public:
    void setState(ConnectionState* state) {
        delete m_state;
        m_state = state;
    }
    
    void connect() { m_state->connect(); }
    void disconnect() { m_state->disconnect(); }
    void sendData(const QByteArray& data) { m_state->sendData(data); }
    
private:
    ConnectionState* m_state = new DisconnectedState();
};

七、代理模式(Proxy)

作用:为其他对象提供一种代理以控制对这个对象的访问。
典型场景

  • 数据库操作的权限控制(如只读代理、读写代理)。
  • 网络请求的缓存代理(避免重复请求相同数据)。

示例代码

// 抽象主题:数据库操作
class DatabaseOperations {
public:
    virtual QSqlQuery executeQuery(const QString& sql) = 0;
    virtual ~DatabaseOperations() {}
};

// 真实主题:实际数据库操作
class RealDatabaseOperations : public DatabaseOperations {
public:
    explicit RealDatabaseOperations(const QSqlDatabase& db) : m_db(db) {}
    
    QSqlQuery executeQuery(const QString& sql) override {
        QSqlQuery query(m_db);
        query.exec(sql);
        return query;
    }
    
private:
    QSqlDatabase m_db;
};

// 代理:只读权限代理
class ReadOnlyDatabaseProxy : public DatabaseOperations {
public:
    explicit ReadOnlyDatabaseProxy(DatabaseOperations* realOps) : m_realOps(realOps) {}
    
    QSqlQuery executeQuery(const QString& sql) override {
        // 检查是否为只读操作(如SELECT语句)
        if (sql.trimmed().toUpper().startsWith("SELECT")) {
            return m_realOps->executeQuery(sql);
        } else {
            qDebug() << "Read-only proxy: write operations are not allowed";
            return QSqlQuery();
        }
    }
    
private:
    DatabaseOperations* m_realOps;
};

八、策略模式(Strategy)

作用:定义一系列算法,将每个算法封装起来,并使它们可以相互替换。
典型场景

  • 根据配置选择不同的数据库加密策略。
  • 网络通信中根据网络状态选择不同的传输协议(如WiFi用HTTP,4G用WebSocket)。

示例代码

// 抽象策略:数据加密
class EncryptionStrategy {
public:
    virtual QByteArray encrypt(const QByteArray& data) = 0;
    virtual QByteArray decrypt(const QByteArray& data) = 0;
    virtual ~EncryptionStrategy() {}
};

// 具体策略:AES加密
class AESEncryption : public EncryptionStrategy {
public:
    QByteArray encrypt(const QByteArray& data) override {
        // 实现AES加密逻辑
        return "AES-encrypted:" + data;
    }
    
    QByteArray decrypt(const QByteArray& data) override {
        // 实现AES解密逻辑
        return data.mid(11);  // 移除"AES-encrypted:"前缀
    }
};

// 具体策略:Base64编码(非加密)
class Base64Encoding : public EncryptionStrategy {
public:
    QByteArray encrypt(const QByteArray& data) override {
        return data.toBase64();
    }
    
    QByteArray decrypt(const QByteArray& data) override {
        return QByteArray::fromBase64(data);
    }
};

// 上下文类
class DataManager {
public:
    void setEncryptionStrategy(EncryptionStrategy* strategy) {
        delete m_strategy;
        m_strategy = strategy;
    }
    
    QByteArray saveData(const QByteArray& data) {
        return m_strategy->encrypt(data);
    }
    
    QByteArray loadData(const QByteArray& encryptedData) {
        return m_strategy->decrypt(encryptedData);
    }
    
private:
    EncryptionStrategy* m_strategy = new Base64Encoding();
};

九、组合模式(Composite)

作用:将对象组合成树形结构以表示“部分-整体”的层次结构,使用户对单个对象和组合对象的使用具有一致性。
典型场景

  • 复杂UI界面的组件管理(如窗口包含多个面板,面板包含多个控件)。
  • 数据库查询条件的组合(如AND/OR逻辑组合多个查询条件)。

示例代码

// 抽象组件:查询条件
class QueryCondition {
public:
    virtual QString toSql() = 0;
    virtual ~QueryCondition() {}
};

// 叶子节点:简单条件
class SimpleCondition : public QueryCondition {
public:
    SimpleCondition(const QString& field, const QString& op, const QVariant& value)
        : m_field(field), m_op(op), m_value(value) {}
    
    QString toSql() override {
        return QString("%1 %2 '%3'").arg(m_field, m_op, m_value.toString());
    }
    
private:
    QString m_field;
    QString m_op;
    QVariant m_value;
};

// 组合节点:复合条件
class CompositeCondition : public QueryCondition {
public:
    enum Logic { AND, OR };
    
    explicit CompositeCondition(Logic logic) : m_logic(logic) {}
    
    void addCondition(QueryCondition* condition) {
        m_conditions.append(condition);
    }
    
    QString toSql() override {
        if (m_conditions.isEmpty()) return "";
        
        QString sql = "(";
        for (int i = 0; i < m_conditions.size(); ++i) {
            sql += m_conditions[i]->toSql();
            if (i < m_conditions.size() - 1) {
                sql += (m_logic == AND) ? " AND " : " OR ";
            }
        }
        sql += ")";
        return sql;
    }
    
private:
    Logic m_logic;
    QList<QueryCondition*> m_conditions;
};

总结:设计模式选择指南

功能模块推荐设计模式原因
数据库操作MVC/MVVM、单例、命令、工厂分离数据与视图,统一数据库连接,支持批量操作和多数据库适配
网络通信单例、观察者、状态、策略全局唯一连接,监听消息变化,管理连接状态,动态切换协议
界面逻辑与显示MVC/MVVM、观察者、组合分离界面与数据,实现界面间通信,管理复杂UI结构
权限与缓存控制代理模式控制对资源的访问,缓存频繁请求的数据
配置与扩展性工厂、策略、抽象工厂根据配置动态创建对象,灵活切换算法或数据库类型

建议

  1. 优先使用Qt框架内置的模式(如MVC、信号槽),避免重复造轮子。
  2. 从简单设计开始,仅在必要时引入模式(如复杂度增加、需求变更频繁)。
  3. 结合UML图设计架构,确保模式的合理应用,避免过度设计。
C++ Qt设计模式(第2版)是美国萨福克大学已使用十余年的经典教程,利用跨平台开源软件开发框架Qt阐释了C++和设计模式中的主要思想。全书共分四个部分:第一部分介绍C++、UML、Qt、模型-视图、SQL、XML、设计模式等基础知识,目的是为零基础的C++初学者铺垫一条学习面向对象编程的快捷之路;第二部分讲解内存访问、继承等重要的C++特性,是前一部分的延伸和拓展;第三部分使用Phonon编写了一个多媒体播放器,展示了主要技术理念的应用方法;附录部分给出了C++保留关键字、Debian和Qt程序开发环境的配置等内容。每节的练习题和各章后面的复习题,既可作为课堂上的讨论题,也可进一步启发读者对于关键知识点的思考。 C++ Qt设计模式(第2版)目录 第一部分 设计模式Qt 第1章 C++简介 2 第2章 类与对象 46 第3章 Qt简介 78 第4章 列表 85 第5章 函数 94 第6章 继承与多态 116 第7章 库与设计模式 163 第8章 QObject, QApplication,信号和槽 179 第9章 窗件和设计师 195 第10章 主窗口和动作 225 第11章 范型和容器 246 第12章 元对象,属性和反射编程 262 第13章 模型和视图 277 第14章 验证和正则表达式 302 第15章 XML解析 318 第16章 更多的设计模式 335 第17章 并发 353 第18章 数据库编程 376 第二部分 C++语言规范 第19章 类型与表达式 386 第20章 作用域与存储类 416 第21章 内存访问 431 第22章 继承详解 443 第三部分 编 程 作 业 第23章 MP3自动点唱机作业 456
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值