【设计模式 - 结构型模式】2. 桥接模式
作者:互联网
一、定义
考虑这样一个需求:绘制矩形、圆形、三角形这三种图案。按照面向对象的理念,我们至少需要个具体类,对应三种不同的图形。
// 抽象形状类IShape
class IShape {
public:
void draw();
};
// 三个具体形状类:矩形、圆形、三角形
class Rectangle: public IShape {
public:
void draw() {
cout << "绘制矩形" << endl;
}
};
class Round: public IShape {
public:
void draw() {
cout << "绘制圆形" << endl;
}
};
class Triangle: public IShape {
public:
void draw() {
cout << "绘制三角形" << endl;
}
};
接下来我们有了新的需求,每种形状都需要有四种不同的颜色:红、蓝、黄、绿。
这时我们很容易想到两种设计方案:
- 为了复用形状类,将每种形状定义为父类,每种不同颜色的图形继承自其形状父类。此时一共有 12 个类。
- 为了复用颜色类,将每种颜色定义为父类,每种不同颜色的图形继承自其颜色父类。此时一共有 12 个类。
乍一看没什么问题,我们使用了面向对象的继承特性,复用了父类的代码并扩展了新的功能。
但仔细想想,如果以后要増加一种颜色,比如黑色,那么我们就需要增加三个类;如果再要增加一种形状,我们又需要增加五个类,对应 5 种颜色。更不用说遇到增加 20 个形状,20 种颜色的需求,不同的排列组合将会使工作量变得无比的庞大。看来我们不得不重新思考设计方案。
形状和颜色,都是图形的两个属性。他们两者的关系是平等的,所以不属于继承关系。更好的的实现方式是:将形状和颜色分离,根据需要对形状和颜色进行组合,这就是桥接模式的思想。
桥接模式:将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体模式或接口模式。
官方定义非常精准、简练,但却有点不易理解。通俗地说,如果一个对象有两种或者多种分类方式,并且两种分类方式都容易变化,比如本例中的形状和颜色。这时使用继承很容易造成子类越来越多,所以更好的做法是把这种分类方式分离出来,让他们独立变化,使用时将不同的分类进行组合即可。
二、结构
桥接(Bridge)模式包含以下主要角色。
- 抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
- 扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
- 实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
- 具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。
其结构图如下图所示:
二、程序实现
实现程序如下:
#include <iostream>
#include <string>
using namespace std;
// 实现化角色: 颜色类IColor
class IColor {
public:
virtual string getColor() = 0;
};
// 具体实现化角色A
class Red: public IColor {
public:
string getColor() {
return "红";
}
};
// 具体实现化角色B
class Blue: public IColor {
public:
string getColor() {
return "蓝";
}
};
// 具体实现化角色C
class Yellow: public IColor {
public:
string getColor() {
return "黄";
}
};
// 具体实现化角色D
class Green: public IColor {
public:
string getColor() {
return "绿";
}
};
// 抽象化角色: 形状类IShape
class IShape {
public:
virtual void setColor(IColor *color) = 0;
virtual void draw() = 0;
};
// 扩展抽象化角色A
class Rectangle: public IShape {
public:
void setColor(IColor *color) {
this->m_color = color;
}
void draw() {
cout << "绘制" << m_color->getColor() << "矩形" << endl;
}
private:
IColor *m_color;
};
// 扩展抽象化角色B
class Round: public IShape {
public:
void setColor(IColor *color) {
this->m_color = color;
}
void draw() {
cout << "绘制" << m_color->getColor() << "圆形" << endl;
}
private:
IColor *m_color;
};
// 扩展抽象化角色C
class Triangle: public IShape {
public:
void setColor(IColor *color) {
this->m_color = color;
}
void draw() {
cout << "绘制" << m_color->getColor() << "三角形" << endl;
}
private:
IColor *m_color;
};
int main()
{
Rectangle *rectangle = new Rectangle();
rectangle->setColor(new Red());
rectangle->draw();
Round *round = new Round();
round->setColor(new Blue());
round->draw();
Triangle *triangle = new Triangle();
triangle->setColor(new Yellow());
triangle->draw();
return 0;
}
输出如下:
绘制红矩形
绘制蓝圆形
绘制黄三角形
这时我们再来回顾一下官方定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。抽象部分指的是父类,对应本例中的形状类,实现部分指的是不同子类的区别之处。将子类的区别方式——也就是本例中的颜色——分离成接口,通过组合的方式桥接颜色和形状,这就是桥接模式,它主要用于两个或多个同等级的接口。
参考:
标签:draw,角色,桥接,getColor,模式,class,形状,设计模式,public 来源: https://www.cnblogs.com/linuxAndMcu/p/13678929.html