【QA】策略模式在QT有哪些应用
在 Qt 框架中,策略模式(Strategy Pattern)被广泛应用于多个模块,通过将算法或行为封装为独立的类,使得它们可以在运行时动态替换。以下是一些典型的例子:
1. 布局管理器(Layout Managers)
- 策略接口:
QLayout
(抽象基类) - 具体策略:
QHBoxLayout
、QVBoxLayout
、QGridLayout
等。 - 上下文:
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:
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;
}
3. 模型/视图框架中的代理(Item Delegates)
- 策略接口:
QAbstractItemDelegate
。 - 具体策略:
QItemDelegate
、QStyledItemDelegate
或自定义代理。 - 上下文:
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;
}
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:
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;
}
策略模式的核心优势
- 解耦:算法实现与使用它的类分离。
- 可扩展性:新增策略无需修改现有代码。
- 运行时动态切换:通过替换策略对象改变行为。
这些例子体现了 Qt 如何通过策略模式提高灵活性和可维护性,开发者可以借鉴这些设计思想优化自己的代码结构。