在Qt應用程序開發中,結合數據庫操作、通信、界面邏輯和顯示等功能,以下是常用的設計模式及其典型應用場景:
一、MVC/MVVM(模型-視圖-控制器/視圖模型)
作用:分離數據(模型)、界面(視圖)和業務邏輯(控制器/視圖模型),提升可維護性。
Qt實現:
- MVC:Qt提供
QAbstractItemModel
、QListView
/QTableView
等組件,支持數據與視圖分離。 - MVVM:結合Qt的屬性系統和信號槽,通過
QObject
和Q_PROPERTY
實現視圖模型。
典型場景:
- 數據庫查詢結果的表格展示(如
QSqlTableModel
與QTableView
結合)。 - 表單數據的雙向綁定(視圖變化自動更新模型,反之亦然)。
示例代碼:
// 模型(數據庫操作)
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結構 |
權限與緩存控制 | 代理模式 | 控制對資源的訪問,緩存頻繁請求的數據 |
配置與擴展性 | 工廠、策略、抽象工廠 | 根據配置動態創建對象,靈活切換算法或數據庫類型 |
建議:
- 優先使用Qt框架內置的模式(如MVC、信號槽),避免重復造輪子。
- 從簡單設計開始,僅在必要時引入模式(如復雜度增加、需求變更頻繁)。
- 結合UML圖設計架構,確保模式的合理應用,避免過度設計。