2018-09-20 10:53:13ios
滥用继承会带来麻烦(实际上何止是麻烦,还会带来性能上的额外开销,关于继承的问题,能够查看继承相关的文章)。好比,对象的继承关系是在编译时就定义好了,因此没法在运行时改变从父类继承的实现。子类实现与它的父类有很是紧密的依赖关系。以致于父类中的任何变化必然会致使子类发生变化。当你须要复用子类时,若是继承下来的实现不适合解决新的问题,则父类必须重写或被其它更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。致使这种问题的缘由是继承是一种强耦合的关系,是is -a 的关系。设计模式
优先使用对象合成、聚合,而不是类继承。(想一下两种模式的适配器,更推荐使用对象适配器就是这个原则的体现了)ide
合成(Composition,有时也叫组合)和聚合都是关联的特殊种类。聚合表示一种弱的拥有关系,体现的是A对象能够包含B对象,可是B对象不是A对象的一部分;合成则是一种强的拥有关系,体现了严格的总体和部分的关系,部分和总体的生命周期是同样的。优先使用对象的聚合、合成将有助于你保持每一个类被封装,并被集中在单个任务上,这样类和类的继承就会保持较小的规模,而且不太可能增加为不可控制的庞然大物。性能
聚合和组合关系,这实际上是须要从宏观上来理解的,而不能从微观角度理解。组合必然是几个组件,你们每一个都不能少,少了就不是一个总体,这是一个强拥有的关系。而聚合,多你一个很少,少你一个很多,就像《大话设计模式》里讲的大雁和雁群的关系,大雁A、大雁B、大雁C、大雁D等无数多只大雁聚合在一块儿就是一个雁群,但是你能说大雁A离开了雁群这个雁群就不是雁群了吗?显然不能。可是在具体实现上,其实大都是以类的数据成员来实现的。最多就是在组合的状况下class内嵌套class,可是这种作法并很差,由于过多的嵌套,可能会形成这个类的臃肿。编码
桥接模式(Bridge),将抽象部分与它的实现部分分离,使它们均可以独立地变化。这里的抽象与它的实现分离,并非指让抽象类和派生类分类,这没有任何意义。实现指的是抽象类和它的派生类用来实现本身的对象。其实就是说,一个系统的实现,可能有多个角度的分类,每一种分类都有可能变化,那么就把这种多角度分离出来让它们独自变化。举例来讲,手机便可以按照品牌分类(手机是抽象,功能是实现),也能够按照功能分类(功能是实现,而手机变成了抽象)。spa
按照品牌分类实现类图:设计
按照功能分类实现结构图:3d
能够看到上面两种接口图,模块与模块之间有着极强的耦合度,对按照手机品牌分类的结构中,当有新手机品牌加入的时候,你须要为这一款手机从新开发功实现TaoBao、Game(我知道你会说软件会兼容,可是这里暂时不考虑这个,就假设没有兼容性)。对按照功能来进行分类的时候,每增长一个新功能就要为对应的品牌独立开发相应的功能。指针
实现方式是多种多样的,而桥接模式的核心意图就是把实现独立出来,让它们各自独立的变化,而且它们本身的变化不会影响到其它的实现,从而达到应对变化的目的。按照桥接的思路进行设计结构图以下:code
优势:
1.桥接分离了抽象和实现的具体联系,使得实现和抽象均可以去按照各自的维度去变化,并且相互之间不会产生影响。所谓隔离了抽象和实现,其实就是经过聚合的方式来实现了组件的动态添加和离开,子类不一样形式的组合可以构建出不一样的对象。
2.在设计上它能够用来代替多层继承方案。当继承体系达到了必定深度以后,会致使大量的子类,以及冗余的功能,而且子类自己的管理也是一个问题。
3.桥接模式提升了系统的可扩展性,由于抽象和实现,能够按照各自不一样的维度进行变化,进而组合出不一样的类型
缺点:
1.增长了设计和理解难度,由于关联关系从一开始就是创建在抽象层面的,意味着编码工做要针对抽象层进行。
2.桥接模式要求系统正确的识别各个独立变化的维度,可是识别这些维度也须要必定的考量。
桥接模式使用的关键是分清楚谁是实现,谁是抽象。假设咱们有一间很是大的图书馆,馆藏丰富,内含n个区域,每一个区域中有不一样种类的书籍,每一个图书管理员负责其中一各区域。那图书管理员则是一个抽象。由于图书是客观存在的,它不会由于图书管理员的离开而消失。。也就是说咱们能够经过实现的子类和抽象的子类进行组合,可得出任意形状的系统。使用桥接模式。图书区内上架什么书或者下架什么书,对图书管理员不会产生影响(只要保持方法稳定)。
1.实现的基类(UML类图中的Implementor)
#ifndef IMPLEMENTOR_H_ #define IMPLEMENTOR_H_ class Implementor { public: virtual void display()=0; Implementor() = default; virtual ~Implementor() = default; }; #endif
2.实现的具体类(UML类图中的ConcreteImplementor)
#ifndef IMPLEMENTOR1_H_ #define IMPLEMENTOR1_H_ #include "Implementor.h" #include <iostream> class Implementor1:public Implementor { public: void display() override; Implementor1() = default; ~Implementor1() = default; }; #endif #include "Implementor1.h" void Implementor1::display() { std::cout << "Book1 " << std::endl; }
3.抽象的基类(UML类图中的Abstraction)
#ifndef ABSTRACT_H_ #define ABSTRACT_H_ #include "Implementor.h" class Abstract { public: virtual void sell() = 0; Abstract() = default; virtual ~Abstract() = default; protected: Implementor* m_pobjImplementor{nullptr}; }; #endif
4.抽象的具体类(UML类图中的RefinedAbstraction)
#ifndef REFINEDABSTRACTION1_H_ #define REFINEDABSTRACTION1_H_ #include "Abstract.h" #include <string> #include <iostream> class RefinedAbstraction1:public Abstract { public: void sell() override; RefinedAbstraction1(std::string strName,Implementor* objImplementor): m_strName(strName) { m_pobjImplementor = objImplementor; } private: std::string m_strName; }; #endif #include "RefinedAbstraction1.h" void RefinedAbstraction1::sell() { if(nullptr != m_pobjImplementor) { std::cout << "My name is:" << m_strName<<".I am responsible for " << std::endl; m_pobjImplementor->display(); } }
5.客户端代码(main)
#include "RefinedAbstraction1.h" #include "Implementor1.h" #include "Abstract.h" int main(int argc,char *aargv[]) { Implementor1 objConcreteImplement; RefinedAbstraction1 concreteAbstraction("Yang",&objConcreteImplement); Abstract *ab = &concreteAbstraction; ab->sell(); return (1); }