问题:
方式一,
方式二,
存在问题:
继承带来的麻烦,无论是哪种方式,一旦功能增多、品牌增多,增长不可控的无限变大。增加一个品牌,增加m个软件类+1个品牌类;增加一个软件,增加n(品牌个数)软件个类。
对象的继承关系在编译时就定义好了,所以无法在运行时改变从父类继承的实现。
子类的实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。
当需要复用子类时。如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性,并最终限制了复用性。
解决方式:
合成/聚合复用原则。即优先使用对象合成/聚合,而不是类继承。
合成/聚合复用原则,CARP
定义:
尽量使用合成/聚合,尽量不要使用类继承。
聚合表示一种弱的“拥有”关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分。
合成表示一种强的“拥有”关系,体现了严格的部分和整体的关系,部分和整体的声明周期一样。
优点:
优先使用对象的合成/聚合将有助于你保持每个类被封装,并被集中在单个任务上。这样类、类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物。
实例:
通过对象的职责来考虑问题,而不是结构来考虑问题。软件间、品牌间——合成;品牌与软件——聚合
HandsetSoft:手机软件抽象类
软件具体类
HandsetSoft:品牌抽象类
品牌具体类:
客户端:
优点:
增加软件功能、手机品牌只需要增加一个类就可以了。
符合“开放-封闭原则”,不会修改原来的代码,只是添加扩展类即可。
桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
抽象部分与它的实现部分分离?
不是抽象类与派生类分离。实现,是指抽象类和它的派生类用来实现自己的对象。即手机,可按品牌分类,也可按功能分类。
实现系统可能有多角度分类,每一种分类都有可能变化。就把这种多角度分离出来,让他们独立变化,减少它们之间的耦合。
由于实现的方式有很多种,桥接模式的核心意图就是把这些实现独立出来,让它们各自地变化。这样就使得每种实现的变化不会影响其他实现,从而达到应对变化的目的。
结构图:
Abstraction
RefinedAbstraction
客户端:
扩展:
有了新锤子,所有的东西看上去都成了钉子。
继承
是一种强耦合的接口。
父类变,子类就必须要变。盲目使用继承,会造成麻烦。
优先使用对象的合成会聚合,而不是类继承。使用继承时,一定要优先考虑“is-a”的关系之后,再考虑是否使用,而不是任何时候都去使用。
当发现需要多角度去分类实现的对象,只用继承会造成大量的类增加,不能满足“开放-封闭原则”时,考虑用交接模式。
只要真正深入地理解了设计原则,很多设计模式就是原则的应用而已。