桥接模式:将抽象部分与它的实现部分分离,使它们可以独立地变化。
2.实例设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,
如红色、绿色、蓝色等,此时至少有如下两种设计方案:
- 第一种设计方案是为每一种形状都提供一套各种颜色的版本;
- 第二种设计方案是根据实际需要对形状和颜色进行组合。
对于有两个变化维度(即两个变化的原因)的系统,采用方案二来进行设计系统中类的个数更少,且系统扩展更为方便。
设计方案二即是桥接模式的应用。桥接模式将继承关系转换为关联关系,从而降低了类与类之间的耦合,减少了代码编写量。
桥接模式包含如下角色:
- shape:图形抽象类
- retangle,circle:图形扩充抽象类
- color:颜色实现类接口
- red,yellow:具体颜色实现类
- 4.1 c++代码实现
- 4.1.1 main.cpp
#include#include"shape.hpp" #include"color.hpp" using namespace std; void test_inline_bridge() { color* clr = new yellow(); shape* shp = new circle(clr); shp->draw(); cout << "-----------------------" << endl; clr = new red(); shp = new circle(clr); shp->draw(); cout << "-----------------------" << endl; clr = new red(); shp = new retangle(clr); shp->draw(); cout << "-----------------------" << endl; clr = new yellow(); shp = new retangle(clr); shp->draw(); cout << "-----------------------" << endl; } int main(int argc, const char** argv) { test_inline_bridge(); return 0; }
- 4.1.2 color.hpp
//=========================================================== #ifndef D50611F4_86D1_48F4_BCA6_3AFD4AE61BAC #define D50611F4_86D1_48F4_BCA6_3AFD4AE61BAC #includeusing namespace std; // 颜色抽象接口 class color { public: color(){}; virtual ~color(){}; virtual void choose_color(){}; }; class red: public color { public: red(){}; ~red(){}; void choose_color(){ cout << "choose_color red" << endl; }; }; class yellow: public color { public: yellow(){}; ~yellow(){}; void choose_color(){ cout << "choose_color yellow" << endl; }; }; class blue: public color { public: blue(){}; ~blue(){}; void choose_color(){ cout << "choose_color blue" << endl; }; }; #endif
- 4.1.3 shape.hpp
//=========================================================== #ifndef F45EC17B_C10E_4F7B_A409_1D60017EF5CE #define F45EC17B_C10E_4F7B_A409_1D60017EF5CE #include#include"color.hpp" using namespace std; // 图形抽象接口 class shape { private: color* m_clr; protected: color* get_clr() { return m_clr; } public: shape(color* clr): m_clr(clr) {}; virtual ~shape(){ delete m_clr; }; virtual void draw(){}; }; class circle: public shape { public: circle(color* clr): shape(clr){}; ~circle(){}; void draw(){ cout << "circle::draw" << endl; get_clr()->choose_color(); } }; class retangle: public shape { public: retangle(color* clr):shape(clr){}; ~retangle(){}; void draw(){ cout << "retangle::draw" << endl; get_clr()->choose_color(); } }; class triangle: public shape { public: triangle(color* clr):shape(clr){}; ~triangle(){}; void draw(){ cout << "triangle::draw" << endl; get_clr()->choose_color(); } }; #endif
-
4.2 go代码实现: go实现和c++实现有点不一样, 因为go的接口类不能带有成员变量,故通过参数将其传入,这个安全性没有c++好。
-
4.3 color.go和shape.go在main.go同一级目录的bridge的包下,代码如下:
-
4.3.1:color.go
// color.go
package bridge
import (
"fmt"
)
// ==================================================
// 颜色抽象接口
type IColor interface{
ChooseColor()
}
// ==================================================
type Red struct {
}
func NewRed() *Red {
return &Red{}
}
func (r *Red) ChooseColor() {
fmt.Println("ChooseColor::Red")
}
// ==================================================
type Yellow struct {
}
func NewYellow() *Yellow {
return &Yellow{}
}
func (y *Yellow) ChooseColor() {
fmt.Println("ChooseColor::Yellow")
}
// ==================================================
type Blue struct {
}
func NewBlue() *Blue {
return &Blue{}
}
func (b *Blue) ChooseColor() {
fmt.Println("ChooseColor::Blue")
}
- 4.3.2:shape.go
package bridge
import (
"fmt"
)
// ==================================================
// 图形抽象接口
type IShape interface{
Draw(clr IColor)
}
// ==================================================
type Circle struct {
}
func NewCircle() *Circle {
return &Circle{}
}
func (c *Circle) Draw(clr IColor) {
fmt.Println("Circle::Draw")
clr.ChooseColor()
fmt.Println("---------------------------")
}
// ==================================================
type Retangle struct {}
func NewRetangle() *Retangle {
return &Retangle{}
}
func (r *Retangle) Draw(clr IColor) {
fmt.Println("Retangle::Draw")
clr.ChooseColor()
fmt.Println("---------------------------")
}
- 4.3.3:main.go
package main
import (
"./bridge"
)
func main() {
var ishp bridge.IShape = bridge.NewCircle()
ishp.Draw(bridge.NewRed())
ishp.Draw(bridge.NewYellow())
ishp.Draw(bridge.NewBlue())
var itshp bridge.IShape = bridge.NewRetangle()
itshp.Draw(bridge.NewRed())
itshp.Draw(bridge.NewYellow())
itshp.Draw(bridge.NewBlue())
}
- 4.3.3:执行结果:
Circle::Draw ChooseColor::Red --------------------------- Circle::Draw ChooseColor::Yellow --------------------------- Circle::Draw ChooseColor::Blue --------------------------- Retangle::Draw ChooseColor::Red --------------------------- Retangle::Draw ChooseColor::Yellow --------------------------- Retangle::Draw ChooseColor::Blue ---------------------------5.模式分析
理解桥接模式,重点需要理解如何将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化。
- 抽象化:抽象化就是忽略一些信息,把不同的实体当作同样的实体对待。
在面向对象中,将对象的共同性质抽取出来形成类的过程即为抽象化的过程。 - 实现化:针对抽象化给出的具体实现,就是实现化,抽象化与实现化是一对互逆的概念,
实现化产生的对象比抽象化更具体,是对抽象化事物的进一步具体化的产物。 - 脱耦:脱耦就是将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联,
将两个角色之间的继承关系改为关联关系。桥接模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用关联关系(组合或者聚合关系)而不是继承关系,
从而使两者可以相对独立地变化,这就是桥接模式的用意。



