设计模式:桥接模式

2024-01-07 18:23:29

1. 定义

桥接模式(Bridge Pattern):旨在将抽象部分和实现部分解耦,使它们可以独立地变化。这种模式通过将抽象和实现分离,使它们可以独立地进行扩展和修改,而不会相互影响。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。

2. 画笔问题

假如需要使用大、中、小3种型号的画笔来绘制红、黑、蓝3种不同的颜色。如果我们使用工厂模式,就需要支持9种规格的笔的制造,而且如果红色改色度了,那红大、红中、红小都需要一起改。所以我们使用桥接模式,将颜色与大小分离开,颜色与大小的扩展与修改就不会影响到对方。

#include <iostream>

// 颜色接口
class Color {
public:
    virtual void applyColor() = 0;
};

// 黑色
class BlackColor : public Color {
public:
    void applyColor() override {
        std::cout << "Applying black color." << std::endl;
    }
};

// 红色
class RedColor : public Color {
public:
    void applyColor() override {
        std::cout << "Applying red color." << std::endl;
    }
};

// 蓝色
class BlueColor : public Color {
public:
    void applyColor() override {
        std::cout << "Applying blue color." << std::endl;
    }
};

// 画笔抽象类
class Brush {
protected:
    Color* color;

public:
    Brush(Color* color) : color(color) {}

    virtual void draw() = 0;
};

// 大画笔
class LargeBrush : public Brush {
public:
    LargeBrush(Color* color) : Brush(color) {}

    void draw() override {
        std::cout << "Using large brush. ";
        color->applyColor();
    }
};

// 中画笔
class MediumBrush : public Brush {
public:
    MediumBrush(Color* color) : Brush(color) {}

    void draw() override {
        std::cout << "Using medium brush. ";
        color->applyColor();
    }
};

// 小画笔
class SmallBrush : public Brush {
public:
    SmallBrush(Color* color) : Brush(color) {}

    void draw() override {
        std::cout << "Using small brush. ";
        color->applyColor();
    }
};

int main() {
    // 创建不同型号和颜色的画笔
    Color* blackColor = new BlackColor();
    Color* redColor = new RedColor();
    Color* blueColor = new BlueColor();

    Brush* largeBrush = new LargeBrush(blackColor);
    Brush* mediumBrush = new MediumBrush(redColor);
    Brush* smallBrush = new SmallBrush(blueColor);

    // 使用不同型号和颜色的画笔进行绘画
    largeBrush->draw();
    mediumBrush->draw();
    smallBrush->draw();

    // 释放内存
    delete blackColor;
    delete redColor;
    delete blueColor;
    delete largeBrush;
    delete mediumBrush;
    delete smallBrush;

    return 0;
}

我们定义了Color接口和具体的颜色类BlackColor、RedColor和BlueColor,用于表示不同的颜色。然后,我们定义了Brush抽象类和具体的画笔类LargeBrush、MediumBrush和SmallBrush,用于表示不同的画笔型号。在画笔类中,通过组合颜色类来实现画笔和颜色的桥接。

在main函数中,我们创建了不同型号和颜色的画笔对象,并使用它们进行绘画操作。通过桥接模式,我们可以方便地扩展画笔和颜色的种类,而且它们之间的变化是相互独立的,改变一方不会影响到另一方。

但是看到这个实现,用东北话说有一种咋看咋不得劲的感觉,就是颜色是分离出去了,但是大小这属性还是和笔紧紧绞在一起。我们尝试将颜色与大小都分离出来,进一步增加灵活性。

#include <iostream>

// 笔的颜色的虚基类
class Color {
public:
    virtual std::string getColor() const = 0;
};

// 具体的笔的颜色类
class BlackColor : public Color {
public:
    std::string getColor() const override {
        return "Black";
    }
};

class RedColor : public Color {
public:
    std::string getColor() const override {
        return "Red";
    }
};

class BlueColor : public Color {
public:
    std::string getColor() const override {
        return "Blue";
    }
};

// 笔的大小的虚基类
class Size {
public:
    virtual std::string getSize() const = 0;
};

// 具体的笔的大小类
class SmallSize : public Size {
public:
    std::string getSize() const override {
        return "Small";
    }
};

class MediumSize : public Size {
public:
    std::string getSize() const override {
        return "Medium";
    }
};

class LargeSize : public Size {
public:
    std::string getSize() const override {
        return "Large";
    }
};

// 笔类
class Brush {
private:
    const Size* size;
    const Color* color;

public:
    Brush(const Size* s, const Color* c)
        : size(s), color(c) {}

    void draw() const {
        std::cout << "Using " << size->getSize() << " brush to draw with " << color->getColor() << " color" << std::endl;
    }
};

int main() {
    const Size* smallSize = new SmallSize();
    const Size* mediumSize = new MediumSize();
    const Size* largeSize = new LargeSize();

    const Color* blackColor = new BlackColor();
    const Color* redColor = new RedColor();
    const Color* blueColor = new BlueColor();

    Brush smallBlackBrush(smallSize, blackColor);
    Brush mediumRedBrush(mediumSize, redColor);
    Brush largeBlueBrush(largeSize, blueColor);

    smallBlackBrush.draw();
    mediumRedBrush.draw();
    largeBlueBrush.draw();

    delete smallSize;
    delete mediumSize;
    delete largeSize;
    delete blackColor;
    delete redColor;
    delete blueColor;

    return 0;
}

这个代码看着一下子舒服很多,这也是桥接模式,Brush类作为抽象部分的扩展,将具体的颜色和大小对象组合在一起。

3. 主要优点

(1)分离抽象和实现:桥接模式通过将抽象部分和实现部分分离,使它们可以独立变化。这样可以更灵活地扩展和修改系统的功能,而不会影响到其他部分的代码。

(2)扩展性强:由于抽象部分和实现部分解耦,可以很方便地扩展新的抽象部分和实现部分,而且它们之间可以自由组合,避免了类爆炸问题。

(3)避免多重继承:在很多情况下,桥接模式可以取代多层继承方案。多层继承方案违背了单一职责原则,复用性较差,且类的个数非常多。桥接模式是比多层继承方案更好的解决方法,它极大地减少了子类的个数。

(4)可维护性高:桥接模式将系统划分为多个维度,使得每个维度都相对独立。这样在修改或维护某个维度时,不会对其他维度产生影响,降低了代码的复杂性。

(5)提高了系统的灵活性:通过桥接模式,可以动态地切换和组合不同的抽象部分和实现部分,以满足不同的需求,使得系统更加灵活可配置。

4. 主要缺点

(1)增加了系统的复杂性:桥接模式需要定义抽象部分和实现部分的接口和类,增加了系统的复杂性。当系统的维度较多时,可能需要创建大量的类和接口,导致代码结构复杂。

(2)增加了系统的开销:由于桥接模式需要通过对象组合实现抽象部分和实现部分的桥接,可能会增加一定的对象开销和运行时开销。

(3)对客户端的要求较高:使用桥接模式时,客户端需要了解抽象部分和实现部分的接口和类,以正确组合它们。这要求客户端具有一定的理解和使用桥接模式的能力。

5. 应用场景

桥接模式适用于以下场景:

(1)当你希望将抽象部分和实现部分分离,使它们可以独立地变化时,可以使用桥接模式。这样可以避免在继承关系中产生类爆炸的问题。

(2)当你有多个维度的变化,而且希望能够在运行时动态地组合这些变化时,可以使用桥接模式。例如,如果有多种颜色和多种形状,你希望能够按照需要组合不同的颜色和形状,那么桥接模式可以提供这种灵活性。

(3)当你希望在抽象部分和实现部分之间建立一个稳定的关联关系,并且可以扩展和变化这些部分时,可以使用桥接模式。这样可以避免在抽象和实现之间紧密耦合,使得它们可以独立地发展。

(4)当你希望实现继承的多态性,但又不希望使用继承来实现所有可能的组合时,可以使用桥接模式。桥接模式可以将继承关系转换为对象的组合关系,从而更加灵活地实现多态性。

总之,桥接模式适用于需要将抽象和实现分离、有多个维度的变化、需要建立稳定关联关系和实现多态性的场景。它可以提高系统的灵活性、可扩展性和可维护性。

文章来源:https://blog.csdn.net/weixin_40179091/article/details/135433230
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。