10_01 结构模式 - 桥梁-装饰者-适配器
1. Bridge
继承复用的优点
- 可以很容易地修改或扩展父类的实现
继承复用的缺点
- 继承破坏封装,因为父类的实现细节完全暴露给子类(白盒复用)
- 父类的实现发生改变,则子类必受牵连
- 继承是静态的,不能在运行时发生改变,不灵活
组合复用的优点
- 不破坏封装,这种复用是黑盒复用,因为成员对象的内部细节对新对象保密
- 所需依赖少(只依赖接口)
- 是动态的,可以把成员对象动态替换为另一个类型相同的对象
组合复用的缺点
- 对象数量会增加
- 使用委托(delegation)会使得系统复杂
当需要应对变化的时候,应该首先使用组合的方式,而不是继承——因为组合更加灵活
使用“组合”思路考虑问题
- “汽车”拥有某种或某些“Transmission” ,手动档、自动档、手自一体
- “汽车”和“Transmission”独立变化,互不影响
将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化
意图
- 将抽象部分与它的实现部分分离,使它们都可以独立地变化
适用性
- 抽象和它的实现部分可以独立变化
- 类的抽象以及它的实现都可以通过生成子类的方法加以扩充
实现部分的修改不会对客户产生影响
2. 设计原则:封装可变性
- 可变性因素封装成为一个抽象层,同一种可变性的具体表现映射为同一个抽象类(或者接口)的不同子类。
- 实现可变性和不可变性的分离
- 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
- 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
- 为分离了的抽象部分和实现部分搭桥,目的是使得抽象与实现可以独立变化,都可以分别扩充
- 桥接模式中的桥接是单向的,即只能是抽象部分的对象去使用具体实现部分的对象,反之不可 (疑惑)
可变的封装原则
- 找到系统的可变因素,将它封装起来。这是对“开-闭”原则最好的实现。
- 将可变的因素,封装起来。并且不要把所有的可变因素封装在一起。
- 最好的解决办法是,分块封装可变因素
蜡笔和毛笔的差别
- 蜡笔:笔和颜色无法分离,因此需要36种蜡笔
- 毛笔:笔和颜色可以独立选择,因此只有3+12=15个子类
体现了Bridge模式 - 将继承关系转换为组合关系,从而降低了系统间的耦合,减少了代码冗余
3. 设计模式-装饰者模式(油漆工)
模式结构(重要)
- 抽象构件(Component)角色:组件对象的接口,可以给这些对象动态地添加职责
- 具体构件(Concrete Component)角色:实现组件对象接口,通常就是被装饰者装饰的原始对象,也就是可以给这个对象添加职责。
- 装饰者(Decorator)角色:所有装饰者的抽象父类,需要定义一个与组件接口一致的接口,并持有一个Component对象,其实就是持有一个被装饰的对象。
- 具体装饰者(Concrete Decorator)角色:实际的装饰者对象,实现具体要向被装饰对象添加的功能。
实例
- 装饰会将用户的请求转发给相应的组件(即调用相关的方法),并可能在转发的前后做一些额外的动作(如添加滚动条)。通过这种方法,我们可以根据组合对文本区嵌套不同的装饰,从而添加任意多的功能。这种动态的对对象添加功能的方法不会引起类的爆炸,也具有了更多的灵活性。
本质
- 动态组合:动态为对象增加新的职责
- 与生成子类相比,它更具有灵活性
- 在不改变原有对象的基础之上,将功能附加到对象上。提供了比继承更有弹性的替代方案(扩展原有对象功能)
优点:
- 继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能。(继承在扩展功能是静态的,必须在编译时就确定好,而使用装饰者可以在运行时决定,装饰者也建立在继承的基础之上的)
- 通过使用不同装饰类以及这些类的排列组合,可以实现不同的效果。
- 松耦合
- 符合开闭原则
4. Adapter(适配器)模式
- 将一个类的接口转换成客户希望的另外一个接口
- 使得原来由于接口不兼容而不能一起工作的那些类可以一起工作
- 实现方式:
- 两个类(接口)A,B,定义一个类C来实现B的接口,然后在其内部实现时,转调A类已经实现的功能,这样可以通过对象组合的方式,既复用了A的功能,同时又在接口上满足了B调用的要求
意图
- 将一个类的接口转换成客户希望的另外一个接口
- Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
END