美文网首页
Qt源码中的设计模式:绘图系统与桥接模式

Qt源码中的设计模式:绘图系统与桥接模式

作者: 饮茶先啦靓仔 | 来源:发表于2023-05-10 23:48 被阅读0次

桥接模式

桥接模式(Bridge Pattern)是一种用于将抽象部分和实现部分分离的设计模式。它通过将实现部分抽象化,使得抽象部分和实现部分可以独立地变化,从而实现系统的松耦合和可扩展性。

在桥接模式中,抽象部分和实现部分分别由两个抽象类或接口来定义,并通过一个桥接接口来将它们连接起来。这样,在系统需要增加新的抽象部分或实现部分时,只需要扩展抽象类或实现类,而不需要修改原有的代码,从而实现系统的可扩展性和灵活性。

桥接模式UML类图

上面两段话是不是非常令人困惑?没关系,GoF原本的描述就是这样的,这也让我很迷惑。不用担心,接下来我会努力用人话以及程序实例说明桥接模式的意义所在。我个人的理解是,如UML类图所示,Abstraction类和Implmentor类是组合关系(Abstraction has a Implmentor),表现为Abstraction类可能拥有一个Implmentor类的成员变量。Implmentor类作为Abstraction类的一种属性存在,而桥接模式则通过一种扩展性更好的方式,形成了一种类之间组合关系的结构。

举个例子,假设有一个图形库,其中包含多种不同的图形(如圆形、矩形等)和多种不同的颜色(如红色、蓝色等)。如果使用桥接模式,可以将图形和颜色分别抽象化,分别由两个抽象类定义,并通过一个桥接接口将它们连接起来。这样,在需要增加新的图形或颜色时,只需要扩展对应的抽象类或实现类,而不需要修改原有的代码,从而实现系统的可扩展性和灵活性。

#include <iostream>

// 颜色接口,可以对应UML中的Implmentor类
class Color {
public:
    virtual void draw() = 0;
};

// 红色实现类,可以对应UML中的ConcreteImplmentorA类
class RedColor : public Color {
public:
    void draw() {
        std::cout << "draw in red color." << std::endl;
    }
};

// 蓝色实现类,可以对应UML中的ConcreteImplmentorB类
class BlueColor : public Color {
public:
    void draw() {
        std::cout << "draw in blue color." << std::endl;
    }
};

// 图形接口,可以对应UML中的Abstraction类
class Shape {
protected:
    Color* color_;
public:
    Shape(Color* color) : color_(color) {}
    virtual void draw() = 0;
};

// 圆形类,可以对应UML中的RefineAbstraction类
class Circle : public Shape {
public:
    Circle(Color* color) : Shape(color) {}
    void draw() {
        std::cout << "draw a circle, ";
        color_->draw();
    }
};

// 矩形类,可以对应UML中的RefineAbstraction类
class Rectangle : public Shape {
public:
    Rectangle(Color* color) : Shape(color) {}
    void draw() {
        std::cout << "draw a rectangle, ";
        color_->draw();
    }
};

int main() {
    // 创建红色实现类和蓝色实现类
    Color* red = new RedColor();
    Color* blue = new BlueColor();

    // 创建圆形和矩形,并设置颜色
    Shape* circle = new Circle(red);
    Shape* rectangle = new Rectangle(blue);

    // 绘制图形
    circle->draw();
    rectangle->draw();

    // 释放内存
    delete red;
    delete blue;
    delete circle;
    delete rectangle;

    return 0;
}

在上面的示例中,我们定义了一个颜色接口和两个颜色实现类(红色实现类和蓝色实现类),以及一个图形接口和两个图形类(圆形类和矩形类)。在图形类中,我们使用了一个颜色对象来表示图形的颜色,从而将抽象部分和实现部分分离。在main函数中,我们创建了红色和蓝色实现类,以及圆形和矩形对象,并设置它们的颜色。最后,我们调用它们的绘制方法来绘制图形。在程序结束时,我们释放了内存(最好养成习惯)。

绘图系统中的桥接模式

在Qt的绘图系统中,QPaintDeviceQWidgetQPaintEngineQRasterPaintEngine这些类的角色和关系,可以用桥接模式来描述。在这个模型中:

  • QPaintDevice可以看作是"抽象部分"(Abstraction)。它定义了一些公共接口,比如width(), height(), logicalDpiX()等,这些接口用于描述一个绘图设备的基本属性。值得注意的是,QPaintDevice有一个paintEngine方法,返回一个QPaintEngine指针。

  • QWidgetQPaintDevice的一个具体子类,它代表了一个可视的窗口。这里,QWidget就是"具体的抽象部分"(RefineAbstraction)。QWidget重写了QPaintDevicepaintEngine方法,并返回QRasterPaintEngine指针

  • QPaintEngine可以看作是"实现部分"(Implmentor)。它定义了一些低级别的绘图接口,比如drawPath(), drawImage()等,这些接口用于在具体的绘图设备上进行绘制。

  • QRasterPaintEngineQPaintEngine的一个具体子类,它实现了在基于光栅的设备上进行绘制。这里,QRasterPaintEngine就是"具体的实现部分"(ConcreteImplmentor)。

这样一来,QPaintDeviceQPaintEngine就形成了一个桥接,使得绘图设备的抽象(比如QWidget)和具体的绘制操作(比如在光栅设备上绘制)能够独立地变化。

在这个桥接模式中,QPainter就扮演了一个"客户端"(Client)的角色(没有在UML类图中画出来,但会在后面的代码示例中体现),它使用QPaintDevice提供的抽象接口,并通过QPaintEngine来进行具体的绘制操作。

可以使用C++程序来描述这几个Qt类的关系。请注意,这只是笔者根据自己对Qt源代码的理解,进行的简单抽象,实际代码与程序实例有一定差异,省略了很多的细节。但用于描述Qt绘图系统如何使用桥接模式,应该是勉强足够的。

class QPaintDevice {
public:
    virtual QPaintEngine* paintEngine() const = 0;  // 纯虚函数
    // 其他方法...
};

class QWidget : public QPaintDevice {
public:
    QPaintEngine* paintEngine() const override {
        // 返回一个QRasterPaintEngine实例
        static QRasterPaintEngine instance;
        return &instance;
    }
    // 其他方法...
};

class QPaintEngine {
public:
    virtual void drawPath(const QPainterPath &path) = 0;  // 纯虚函数
    // 其他方法...
};

class QRasterPaintEngine : public QPaintEngine {
public:
    void drawPath(const QPainterPath &path) override {
        // 在光栅设备上绘制路径
        // 具体实现...
    }
    // 其他方法...
};

class QPainter {
public:
    QPainter(QPaintDevice *device) : device(device), engine(device->paintEngine()) {}
    void drawPath(const QPainterPath &path) {
        engine->drawPath(path);
    }
private:
    QPaintDevice *device;
    QPaintEngine *engine;
};

上面的代码示例中,QPainter是客户端代码,它接受一个QPaintDevice对象,并通过QPaintDevicepaintEngine方法获取对应的QPaintEngine对象。然后在需要绘图时,QPainter会通过QPaintEnginedrawPath方法进行绘制。这样,QPainter就能够在不同的设备上进行绘制,而不需要关心具体的绘制过程是如何实现的。这桥接模式的设计思想:将抽象(QPaintDevice)和实现(QPaintEngine)分离,使得二者可以独立地变化

总结

可以看到,桥接模式很好地体现了依赖倒转原则(Dependency Inversion Principle,DIP)。依赖倒转原则是面向对象设计中的一个重要原则,它要求高层模块不应该依赖低层模块,而是应该依赖于抽象。而桥接模式正是通过将实现部分抽象化,使得抽象部分和实现部分可以独立地变化,从而实现了高层模块对低层模块的解耦,符合了依赖倒转原则。

具体来说,在桥接模式中,抽象部分和实现部分分别由两个抽象类或接口来定义,并通过一个桥接接口来将它们连接起来。高层模块只需要依赖于抽象类或接口,而不需要依赖于具体的实现类,从而实现了依赖倒转。

最后,需要强调,尽管文章大致阐述了Qt绘图系统如何使用桥接模式,但仍强烈建议读者通过对Qt源代码进行调试。实际调试才能完全理解Qt源代码的设计思想,以及Qt设计者如何活用设计模式,学到精髓。

相关文章

  • 设计模式[10]-桥接模式-Bridge Pattern

    1. 桥接模式 桥接模式(Bridge Pattern)是结构性设计模式,可以处理多个维度的对象变化。如果系统中存...

  • 09.桥接模式(结构型)

    桥接模式(结构型) 一、桥接模式概述 桥接模式是一种很实用的结构型设计模式,如果软件系统中某个类存在两个独立变化的...

  • 设计模式-桥接模式

    桥接模式介绍 桥接模式(Bridge Pattern)也称为桥梁模式,是结构型设计模式之一。顾名思义其与现实中的桥...

  • 设计模式之桥接模式

    设计模式之桥接模式 1. 模式定义 桥接模式又称柄体模式或接口模式,它是一种结构性模式。桥接模式将抽象部分与实现部...

  • 设计模式-桥接模式

    设计模式-桥接模式 定义 桥接模式(Bridge Pattern)也称为桥梁模式、接口(Interface)模式或...

  • 设计模式——桥接模式

    设计模式——桥接模式 最近公司组件分享设计模式,然而分配给我的是桥接模式。就在这里记录我对桥接模式的理解吧。 定义...

  • 桥接模式

    设计模式:桥接模式(Bridge)

  • 桥接模式

    介绍 桥接模式(Bridge Pattern) 也称为桥梁模式,是结构型设计模式之一。桥接模式的作用就是连接 "两...

  • Java设计模式——桥接模式

    Java设计模式之桥接模式 回顾 上一期分享了适配器模式,主要为了实现解耦 桥接模式 简介 桥接模式是对象的结构模...

  • app内存优化的九大注意点

    1、慎用桥接模式,虽然从程序的设计角度来看,抽象能够帮助我们创建更加灵活的软件架构。但是在手机系统中,这种设计模式...

网友评论

      本文标题:Qt源码中的设计模式:绘图系统与桥接模式

      本文链接:https://www.haomeiwen.com/subject/sdujsdtx.html