桥接模式
模式定义
桥接模式(Bridge),将抽象部分与它的实现部分分离,使他们均可以独立的变化。什么叫抽象与他的实现分离,这并非说让抽象类与其派生类分离,由于这没有任何意义。实现指的是抽象类和它的派生类用来实现本身的对象。c++
模式动机
-
解决继承带来的问题编程
对象的继承关系是在编译时就定义好的,因此没法再运行时改变从父类继承的实现。子类的实现与他的父类有很是紧密的依赖关系,以致于父类实现中的任何变化必然会致使子类发生变化。当你须要复用子类时,若是继承下来的实现不适合解决新的问题,则父类必须重写或被其余更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。设计模式
-
合成/聚合复用原则(CARP)spa
合成(组合)和聚合都是关联的特殊种类。聚合表示一种弱的‘拥有’关系,体现的是A对象能够包含B对象,但B对象不是A对象的一部分;合成则是一种强的‘拥有’关系,体现了严格的部分和总体的关系,部分和总体的生命周期同样。聚合关系在继承关系不适用的状况下能够作替代。其实只要真正深刻的理解了设计原则,不少设计模式其实就是原则的应用而已,或许在不知不觉中就在使用设计模式了。设计
-
设想若是要绘制矩形、圆形、椭圆、正方形,咱们至少须要4个形状类,可是若是绘制的图形须要具备不一样的颜色,如红色、绿色、蓝色等,此时至少有以下两种设计方案:code
-
第一种设计方案是为每一种形状都提供一套各类颜色的版本。对象
-
第二种设计方案是根据实际须要对形状和颜色进行组合。blog
明显方案二采用聚合的方式组织类结构可以使类的数量减小不少。固然这只是一个简单的例子。继承
-
UML类图
源码实现
-
color.h接口
#ifndef COLOR_H #define COLOR_H #include <QString> class Color { public: Color(){} virtual ~Color(){} virtual QString Name() = 0; protected: QString m_Name; }; class Black : public Color { public: Black(); virtual ~Black(); virtual QString Name(); }; class Red : public Color { public: Red(); virtual ~Red(); virtual QString Name(); }; #endif // COLOR_H
-
color.cpp
#include <QDebug> #include "color.h" Black::Black() { m_Name = "Black"; } Black::~Black() { } QString Black::Name() { return m_Name; } Red::Red() { m_Name = "Red"; } Red::~Red() { } QString Red::Name() { return m_Name; }
-
shape.h
#ifndef SHAPE_H #define SHAPE_H #include "color.h" //抽象类 class Shape { public: Shape(){} virtual ~Shape(){} void SetColor(Color* color); virtual void MyShape() = 0; protected: Color* m_Color; }; class Rectangle : public Shape { public: Rectangle(); ~Rectangle(); virtual void MyShape(); }; class Circle : public Shape { public: Circle(); ~Circle(); virtual void MyShape(); }; #endif // SHAPE_H
-
shape.cpp
#include <QDebug> #include "shape.h" void Shape::SetColor(Color *color) { m_Color = color; } Rectangle::Rectangle() { } Rectangle::~Rectangle() { } void Rectangle::MyShape() { qDebug() << "Rectangle" + QString(" And ") + m_Color->Name(); } Circle::Circle() { } Circle::~Circle() { } void Circle::MyShape() { qDebug() << "Circle" + QString(" And ") + m_Color->Name(); }
-
main.cpp
#include <QCoreApplication> #include "shape.h" #include "color.h" #define DELETEOBJECT(x) if(x != nullptr){delete x; x = nullptr;} int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Color* red = new Red(); Color* black = new Black(); //组合一个黑色的圆和一个红色的方形 Shape* rectangle = new Rectangle(); rectangle->SetColor(red); Shape* circle = new Circle(); circle->SetColor(black); rectangle->MyShape(); circle->MyShape(); DELETEOBJECT(red); DELETEOBJECT(black); DELETEOBJECT(rectangle); DELETEOBJECT(circle); return a.exec(); }
-
运行结果
"Rectangle And Red"
"Circle And Black"
优势
分离抽象接口及其实现部分。
-
桥接模式有时相似于多继承方案,可是多继承方案违背了类的单一职责原则(即一个类只有一个变化的缘由),复用性比较差,并且多继承结构中类的个数很是庞大,桥接模式是比多继承方案更好的解决方法。
-
桥接模式提升了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不须要修改原有系统。
-
实现细节对客户透明,能够对用户隐藏实现细节。
缺点
-
桥接模式的引入会增长系统的理解与设计难度,因为聚合关联关系创建在抽象层,要求开发者针对抽象进行设计与编程。
-
桥接模式要求正确识别出系统中两个独立变化的维度,所以其使用范围具备必定的局限性。
总结
- 桥接模式将抽象部分与它的实现部分分离,使它们均可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
- 桥接模式包含以下四个角色:抽象类中定义了一个实现类接口类型的对象并能够维护该对象;扩充抽象类扩充由抽象类定义的接口,它实现了在抽象类中定义的抽象业务方法,在扩充抽象类中能够调用在实现类接口中定义的业务方法;实现类接口定义了实现类的接口,实现类接口仅提供基本操做,而抽象类定义的接口可能会作更多更复杂的操做;具体实现类实现了实现类接口而且具体实现它,在不一样的具体实现类中提供基本操做的不一样实现,在程序运行时,具体实现类对象将替换其父类对象,提供给客户端具体的业务操做方法。
- 在桥接模式中,抽象化(Abstraction)与实现化(Implementation)脱耦,它们能够沿着各自的维度独立变化。
- 桥接模式的主要优势是分离抽象接口及其实现部分,是比多继承方案更好的解决方法,桥接模式还提升了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不须要修改原有系统,实现细节对客户透明,能够对用户隐藏实现细节;其主要缺点是增长系统的理解与设计难度,且识别出系统中两个独立变化的维度并非一件容易的事情。
- 桥接模式适用状况包括:须要在构件的抽象化角色和具体化角色之间增长更多的灵活性,避免在两个层次之间创建静态的继承联系;抽象化角色和实现化角色能够以继承的方式独立扩展而互不影响;一个类存在两个独立变化的维度,且这两个维度都须要进行扩展;设计要求须要独立管理抽象化角色和具体化角色;不但愿使用继承或由于多层次继承致使系统类的个数急剧增长的系统。