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

【QA】策略模式在QT有哪些应用

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


1. 布局管理器(Layout Managers)

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

示例代码

#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 等)。
#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() 设置代理)。
  • 说明
    代理负责控制数据的显示和编辑方式(如日期选择器、颜色选择器等),可通过替换代理动态改变行为。
#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:重写事件处理函数(直接策略)
#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:动态事件过滤器(运行时策略)
#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 的插件架构允许扩展功能(如图像格式支持、数据库驱动),每个插件提供特定策略的实现。
#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 如何通过策略模式提高灵活性和可维护性,开发者可以借鉴这些设计思想优化自己的代码结构。


http://www.kler.cn/a/594422.html

相关文章:

  • LabVIEW运动控制(二):EtherCAT运动控制器的多轴示教加工应用(下)
  • Unity音频混合器如何暴露参数
  • 用python制作一个俄罗斯方块小游戏
  • js 力扣100题 非负整数加一
  • 大白话详细解读React框架的diffing算法
  • 《剑指数据库:MySQL玄阶查术秘典·下卷》
  • 【c++】【STL】unordered_set 底层实现(简略版)
  • 从O(n²)到O(n):基于累计求和模型的线性递归模式优化与多场景实战
  • 基于Matlab的风力发电系统仿真研究
  • vue3 setup中访问全局变量还用加this吗。原来在组合式API中,需要用this.$loading。在setup中怎么用
  • Docker 容器基础技术:namespace
  • wsl2配置xv6全解(包括22.04Jammy)
  • 人工智能在2025年:各行业现状与变革
  • 【大语言模型_6】mindie启动模型错误整理
  • Linux的I2C总线的原理和结构详解
  • 爬虫 crawler 入门爬取不设防网页 并实现无限增生
  • ip属地和手机定位区别在哪?是什么
  • Android 第四次面试总结(自定义 View 与事件分发深度解析)
  • [密码学实战]Java实现抗量子Kyber512与Dilithium2算法及详解
  • CAN通信转TCP/IP通信协议解析