桥接模式(Bridge Pattern):旨在将抽象部分和实现部分解耦,使它们可以独立地变化。这种模式通过将抽象和实现分离,使它们可以独立地进行扩展和修改,而不会相互影响。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
假如需要使用大、中、小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类作为抽象部分的扩展,将具体的颜色和大小对象组合在一起。
(1)分离抽象和实现:桥接模式通过将抽象部分和实现部分分离,使它们可以独立变化。这样可以更灵活地扩展和修改系统的功能,而不会影响到其他部分的代码。
(2)扩展性强:由于抽象部分和实现部分解耦,可以很方便地扩展新的抽象部分和实现部分,而且它们之间可以自由组合,避免了类爆炸问题。
(3)避免多重继承:在很多情况下,桥接模式可以取代多层继承方案。多层继承方案违背了单一职责原则,复用性较差,且类的个数非常多。桥接模式是比多层继承方案更好的解决方法,它极大地减少了子类的个数。
(4)可维护性高:桥接模式将系统划分为多个维度,使得每个维度都相对独立。这样在修改或维护某个维度时,不会对其他维度产生影响,降低了代码的复杂性。
(5)提高了系统的灵活性:通过桥接模式,可以动态地切换和组合不同的抽象部分和实现部分,以满足不同的需求,使得系统更加灵活可配置。
(1)增加了系统的复杂性:桥接模式需要定义抽象部分和实现部分的接口和类,增加了系统的复杂性。当系统的维度较多时,可能需要创建大量的类和接口,导致代码结构复杂。
(2)增加了系统的开销:由于桥接模式需要通过对象组合实现抽象部分和实现部分的桥接,可能会增加一定的对象开销和运行时开销。
(3)对客户端的要求较高:使用桥接模式时,客户端需要了解抽象部分和实现部分的接口和类,以正确组合它们。这要求客户端具有一定的理解和使用桥接模式的能力。
桥接模式适用于以下场景:
(1)当你希望将抽象部分和实现部分分离,使它们可以独立地变化时,可以使用桥接模式。这样可以避免在继承关系中产生类爆炸的问题。
(2)当你有多个维度的变化,而且希望能够在运行时动态地组合这些变化时,可以使用桥接模式。例如,如果有多种颜色和多种形状,你希望能够按照需要组合不同的颜色和形状,那么桥接模式可以提供这种灵活性。
(3)当你希望在抽象部分和实现部分之间建立一个稳定的关联关系,并且可以扩展和变化这些部分时,可以使用桥接模式。这样可以避免在抽象和实现之间紧密耦合,使得它们可以独立地发展。
(4)当你希望实现继承的多态性,但又不希望使用继承来实现所有可能的组合时,可以使用桥接模式。桥接模式可以将继承关系转换为对象的组合关系,从而更加灵活地实现多态性。
总之,桥接模式适用于需要将抽象和实现分离、有多个维度的变化、需要建立稳定关联关系和实现多态性的场景。它可以提高系统的灵活性、可扩展性和可维护性。