【Q&A】策略模式在QT有哪些应用

在 Qt 框架中,策略模式(Strategy Pattern)被广泛应用于多个模块,通过将算法或行为封装为独立的类,使得它们可以在运行时动态替换。以下是一些典型的例子:


1. 布局管理器(Layout Managers)

  • 策略接口QLayout(抽象基类)
  • 具体策略QHBoxLayoutQVBoxLayoutQGridLayout 等。
  • 上下文QWidget(通过 setLayout() 设置布局策略)。
  • 说明
    不同的布局类实现了控件排列的不同算法。用户可以在运行时动态切换布局策略,而无需修改 QWidget 的代码。

示例代码

cpp 复制代码
#include <QWidget>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>

int main() {
    QWidget *window = new QWidget;  // 上下文
    QPushButton *btn1 = new QPushButton("Button 1");
    QPushButton *btn2 = new QPushButton("Button 2");

    // 具体策略1:水平布局
    QHBoxLayout *hLayout = new QHBoxLayout;
    hLayout->addWidget(btn1);
    hLayout->addWidget(btn2);
    window->setLayout(hLayout);  // 设置策略

    // 具体策略2:垂直布局(运行时动态切换)
    QVBoxLayout *vLayout = new QVBoxLayout;
    vLayout->addWidget(btn1);
    vLayout->addWidget(btn2);
    window->setLayout(vLayout);  // 替换策略

    window->show();
    return 0;
}

UML:
聚合 1 1 <<abstract>> QLayout +addWidget(QWidget*) +setGeometry(QRect) QHBoxLayout +addWidget(QWidget*) +setGeometry(QRect) QVBoxLayout +addWidget(QWidget*) +setGeometry(QRect) QWidget +setLayout(QLayout*)


2. 绘图系统(QPainter 与 QPaintDevice)

  • 策略接口QPaintDevice(抽象基类)。
  • 具体策略QWidget(屏幕绘制)、QImage(离屏渲染)、QPixmap(图像缓存)等。
  • 上下文QPainter(根据不同的 QPaintDevice 选择底层绘制策略)。
  • 说明
    QPainter 的绘制操作(如 drawLine())会根据当前关联的 QPaintDevice 自动适配不同的实现(如 OpenGL、Raster 等)。
cpp 复制代码
#include <QPainter>
#include <QWidget>
#include <QImage>

void drawContent(QPaintDevice *device) {
    QPainter painter(device);  // 上下文绑定策略
    painter.drawLine(0, 0, 100, 100);  // 统一接口
}

int main() {
    QImage image(200, 200, QImage::Format_ARGB32);  // 策略1:离屏绘图
    drawContent(&image);  // 绘制到图像

    QWidget widget;       // 策略2:窗口绘图
    widget.show();
    drawContent(&widget); // 绘制到窗口

    return 0;
}

依赖 <<abstract>> QPaintDevice QImage +bits() +pixelFormat() QWidget +show() +paintEvent(QPaintEvent*) QPainter +drawLine(int, int, int, int) +drawRect(QRect)


3. 模型/视图框架中的代理(Item Delegates)

  • 策略接口QAbstractItemDelegate
  • 具体策略QItemDelegateQStyledItemDelegate 或自定义代理。
  • 上下文QAbstractItemView(如 QTableView 通过 setItemDelegate() 设置代理)。
  • 说明
    代理负责控制数据的显示和编辑方式(如日期选择器、颜色选择器等),可通过替换代理动态改变行为。
cpp 复制代码
#include <QStyledItemDelegate>
#include <QTableView>
#include <QStyleOptionProgressBar>

class ProgressBarDelegate : public QStyledItemDelegate {
public:
    void paint(QPainter *painter, const QStyleOptionViewItem &option, 
               const QModelIndex &index) const override {
        int progress = index.data().toInt();
        QStyleOptionProgressBar bar;
        bar.rect = option.rect;
        bar.progress = progress;
        QApplication::style()->drawControl(QStyle::CE_ProgressBar, &bar, painter);
    }
};

int main() {
    QTableView tableView;
    tableView.setItemDelegate(new ProgressBarDelegate());  // 设置策略
    return 0;
}

聚合 1 1 <<abstract>> QAbstractItemDelegate +paint(QPainter*, QStyleOptionViewItem, QModelIndex) +createEditor(QWidget*, QStyleOptionViewItem, QModelIndex) QStyledItemDelegate +paint(...) +createEditor(...) ProgressBarDelegate +paint(...) QTableView +setItemDelegate(QAbstractItemDelegate*)


4. 事件处理与过滤器(Event Handling)

  • 策略接口 :事件处理函数(如 mousePressEvent())或事件过滤器(QObject::eventFilter())。
  • 具体策略:重写事件处理函数或安装自定义事件过滤器。
  • 上下文QObject 及其子类(如 QWidget)。
  • 说明
    允许通过重写事件函数或动态安装过滤器,灵活改变事件处理逻辑。

代码示例

方式1:重写事件处理函数(直接策略)
cpp 复制代码
#include <QWidget>
#include <QMouseEvent>

class CustomWidget : public QWidget {
protected:
    // 策略1:重写事件处理函数
    void mousePressEvent(QMouseEvent *event) override {
        qDebug() << "CustomWidget: 鼠标按下事件 (" << event->pos() << ")";
        QWidget::mousePressEvent(event);  // 可选:调用基类默认处理
    }
};

// 使用
int main() {
    CustomWidget widget;
    widget.show();
    return 0;
}
方式2:动态事件过滤器(运行时策略)
cpp 复制代码
#include <QObject>
#include <QEvent>
#include <QDebug>

class EventFilter : public QObject {
protected:
    // 策略2:事件过滤器
    bool eventFilter(QObject *watched, QEvent *event) override {
        if (event->type() == QEvent::MouseButtonPress) {
            qDebug() << "EventFilter: 拦截鼠标按下事件";
            return true;  // 拦截事件,阻止进一步传递
        }
        return QObject::eventFilter(watched, event);
    }
};
// 使用
int main() {
    QWidget widget;
    EventFilter *filter = new EventFilter;
    widget.installEventFilter(filter);  // 动态安装策略
    widget.show();
    return 0;
}
复制代码

UML:
继承并重写事件 继承并实现过滤器 安装过滤器(依赖) 1 0..* QObject +eventFilter(QObject*, QEvent*) +installEventFilter(QObject*) QWidget +mousePressEvent(QMouseEvent*) CustomWidget +mousePressEvent(QMouseEvent*) EventFilter +eventFilter(QObject*, QEvent*)


5. 插件系统(Plugins)

  • 策略接口 :预定义的插件接口(如 QImageIOPlugin)。
  • 具体策略:不同插件实现(如支持 PNG、JPEG 格式的插件)。
  • 上下文 :通过 QPluginLoader 动态加载插件。
  • 说明
    Qt 的插件架构允许扩展功能(如图像格式支持、数据库驱动),每个插件提供特定策略的实现。
cpp 复制代码
#include <QPluginLoader>
#include <QImage>

class ImagePluginInterface {
public:
    virtual QImage loadImage(const QString &path) = 0;
};

class PngPlugin : public QObject, public ImagePluginInterface {
    Q_OBJECT
    Q_INTERFACES(ImagePluginInterface)
public:
    QImage loadImage(const QString &path) override {
        return QImage(path).convertToFormat(QImage::Format_ARGB32);
    }
};

int main() {
    QPluginLoader loader("png_plugin.dll");
    ImagePluginInterface *plugin = qobject_cast<ImagePluginInterface*>(loader.instance());
    QImage image = plugin->loadImage("image.png");  // 调用策略
    return 0;
}

实现 依赖 <<interface>> ImagePluginInterface +loadImage(QString) : QImage PngPlugin +loadImage(QString) : QImage QPluginLoader +instance() +load()


策略模式的核心优势

  • 解耦:算法实现与使用它的类分离。
  • 可扩展性:新增策略无需修改现有代码。
  • 运行时动态切换:通过替换策略对象改变行为。

这些例子体现了 Qt 如何通过策略模式提高灵活性和可维护性,开发者可以借鉴这些设计思想优化自己的代码结构。

相关推荐
pianmian17 分钟前
python每日十题(10)
开发语言·python
王有品17 分钟前
python之横条形图实例
开发语言·python
aimmon19 分钟前
Rust从入门到精通之进阶篇:17.宏编程基础
开发语言·后端·rust
aimmon22 分钟前
Rust从入门到精通之入门篇:8.基本数据结构
开发语言·数据结构·rust
布伦鸽22 分钟前
C# Modbus TCP/IP学习记录
开发语言·学习·c#
菜鸟学编程o24 分钟前
C++:类和对象(一)
开发语言·c++·算法
Python数据分析与机器学习25 分钟前
《基于Python的财务数据可视化与决策支持系统开发》开题报告
大数据·开发语言·人工智能·python·深度学习·信息可视化
aimmon1 小时前
Rust从入门到精通之精通篇:25.过程宏高级应用
开发语言·后端·rust
多多*1 小时前
使用事件监听器来处理并发环境中RabbitMQ的同步响应问题
java·开发语言·spring boot·分布式·docker·mybatis
xinxiyinhe1 小时前
Python在图像处理领域的第三方库支持(三)
开发语言·图像处理·python