【设计模式】之桥接模式
定义
桥接模式(Bridge Pattern)定义:将抽象化与实现化分离,使得双方可以独立变化。
当然定义什么的通常都晦涩难懂,咱们还是借助例子来理解。
举例
还是举个例子吧。
假如说,有个图形(Graphics
)接口,具有方法draw()
,他有两个可以变化的维度,形状(Shape
)和颜色(Color
)。怎么实现呢?容易想到这样一种方式:先从Graphics
类继承出矩形(Rectangle
)、圆形(Circle
)等形状子类,再给每个形状子类分别派生出红色矩形(RedRectangle
)、绿色矩形(GreenRectangle
)、红色圆形(RedCircle
)和绿色圆形(GreenCircle
)。
此时的类体系结构如下:
有什么问题?
不难发现,如果我们要新增加一个形状,例如三角形,我们就需要对应增加n个子类(其中n=颜色个数),来使三角形具有不同的颜色。同样,如果我们要增加一种颜色,例如黄色,那么就需要对应增加m个子类(其中m=形状个数),来使所有的形状都具有黄色这种颜色。
事实上,如果我们有m种形状,n种颜色,那么我们一共需要的类的个数为m*n。
这也太可怕了吧!人是喜欢偷懒的动物,谁也不想为了区区几个形状和颜色写这么多个类。而且随着形状和颜色的增加,类的个数的增长速度也会越来越快,造成类爆炸。那有没有一种办法,可以让我们不需要写那么多类呢?答案当然是有的!试试看用组合替代继承会怎样?
咱们还是从Graphics
类派生出各个形状子类,但不同的是,这次改用组合来使形状具有不同颜色,这时的类体系结构如下:
看,采用组合替代继承之后,当我们需要增加一种形状的时候,我们是不是只需要多写一个类了,不用为每个颜色对应增加一个形状类。同样,需要增加一种颜色的时候,也只需要写一个类,不用让每个形状都具有这种颜色。如果我们有m种形状,n种颜色,那么我们就只需要m+n个类就可以了,是不是比m*n要少的多了。
那上面的例子中,每个部分都扮演着什么样的角色呢?
抽象化(Abstraction):如例子中的Graphics
类。
扩展抽象化(Refined Abstraction):由抽象化类派生而来,通过组合关系调用实现化类的相应方法,如例子中的Rectangle
、Circle
等类。
实现化(Implementation):如例子中的Color
类。
具体实现化(Concrete Implementation):如例子中的Red
、Green
等类。
事实上,这只是桥接模式的其中一个使用场景。
使用场景
- 需要在抽象化和实现化角色之间增加更多的灵活性。
- 不希望因为类继承导致类的个数急剧增加。
- 一个系统有两个或多个变化维度且都需要扩展。
优缺点
优点
- 将抽象和具体实现分离开来。
- 提高了系统的可扩展性,改变或增加其中一个变化维度,不需要对另一个变化维度进行修改。
- 对客户隐藏实现细节。
缺点
- 会增加理解难度。(这算缺点吗?)
代码
话不多说,直接上代码(假设已#include
相应头文件并using namespace std;
):
Graphics
类:
class Graphics
{
protected:
Color &color;
public:
Graphics(Color &color) : color(color) { }
virtual void draw() = 0;
}
Rectangle
类:
class Rectangle : public Graphics
{
public:
Rectangle(Color &color) : Graphics(color) { }
void draw() override
{
color.paint("矩形");
}
}
Circle
类:
class Circle : public Graphics
{
public:
Circle(Color &color) : Graphics(color) { }
void draw() override
{
color.paint("圆形");
}
}
Color
类:
class Color
{
public:
virtual void paint(string shape) = 0;
}
Red
类:
class Red : public Color
{
public:
void paint(string shape) override
{
cout << "绘制红色的" << shape << endl;
}
}
Green
类:
class Green : public Color
{
public:
void paint(string shape) override
{
cout << "绘制绿色的" << shape << endl;
}
}
main
函数:
int main(int argc, char *argv[])
{
Red red();
Rectangle rectangle(red);
rectangle.draw();
return 0;
)
本文来自博客园,作者:YVVT_Real,转载请注明原文链接:https://www.cnblogs.com/YWT-Real/p/16711072.html