概述
在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?
如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?
定义:
将抽象和实现解耦,使得两者可以独立地变化。
例子1:设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有如下两种设计方案:
•第一种设计方案是为每一种形状都提供一套各种颜色的版本。 •第二种设计方案是根据实际需要对形状和颜色进行组合。
对于有两个变化维度(即两个变化的原因)的系统,采用方案二来进行设计系统中类的个数更少,且系统扩展更为方便。设计方案二即是桥接模式的应用。桥接模式将继承关系转换为关联关系,从而降低了类与类之间的耦合,减少了代码编写量。
桥接模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用关联关系(组合或者聚合关系)而不是继承关系,从而使两者可以相对独立地变化,这就是桥接模式的用意。
场景实用性
你不希望在抽象和他的实现部分之间有一个固定的邦定关系,如在程序的运行时刻实现部分应该可以被选择或者切换。
2). 类的抽象以及他的视像都可以通过生成子类的方法加以扩充。这时bridge模式使你可以对不同的抽象接口和实现部分进行组合,并对他们进行扩充。
3). 对一个抽象的实现部分的修改应该对客户不产生影响,即客户的代码不需要重新编译。
4). 你想对客户完全隐藏抽象的实现部分。
构建模式的组成
抽象类(Abstraction):定义抽象类的接口,维护一个指向Implementor类型对象的指针
扩充抽象类(RefinedAbstraction):扩充由Abstraction定义的接口
实现类接口(Implementor):定义实现类的接口,该接口不一定要与 Abstraction的接口完全一致;事实上这两个接口可以完全不同。
一般来讲, Implementor接口仅提供基本操作,而 Abstraction则定义了基于这些基本操作的较高层次的操作。
具体实现类(ConcreteImplementor):实现Implementor接口并定义它的具体实现
抽象类(Abstraction)
package com.mystudy.bridge;
/**
* 抽象化角色
* Created by litf on 2017/6/5.
*/
public abstract class AbstractionPayOff {
private ImplementPayOff implementPayOff;
public AbstractionPayOff(ImplementPayOff implementPayOff){
this.implementPayOff = implementPayOff;
}
public void PayOff(){
this.implementPayOff.painAndHappy();
}
public void noPayOff(){
this.implementPayOff.painAndHappy();
}
}
扩充抽象类(RefinedAbstraction)
package com.mystudy.bridge;
/**
* 具体抽象化角色
* Created by litf on 2017/6/5.
*/
public class RefinedAbstraPayOff extends AbstractionPayOff {
public RefinedAbstraPayOff(ImplementPayOff implementPayOff) {
super(implementPayOff);
}
/**
* 扩充
*/
@Override
public void PayOff(){
super.PayOff();
System.out.println("努力工作,工资总会有的!");
}
@Override
public void noPayOff(){
super.noPayOff();
System.out.println("延期发工资,好好工作!");
}
}
实现类接口(Implementor)
package com.mystudy.bridge;
/**
* 实现化角色
* Created by litf on 2017/6/5.
*/
public interface ImplementPayOff {
void painAndHappy();
}
具体实现类(ConcreteImplementor)
package com.mystudy.bridge;
/**
* 具体实现化角色
* Created by litf on 2017/6/5.
*/
public class ImplementLoadingPayOff implements ImplementPayOff {
@Override
public void painAndHappy() {
System.out.println("等待发工资好煎熬。。。。");
}
}
具体实现类(ConcreteImplementor)
package com.mystudy.bridge;
/**
* 具体实现化角色
* Created by litf on 2017/6/5.
*/
public class ImplementLife implements ImplementPayOff {
@Override
public void painAndHappy() {
System.out.println("生活就像开发,一直在努力调试期望正常运行");
}
}
客户
package com.mystudy.bridge;
/**
* Created by litf on 2017/6/5.
*/
public class Client {
public static void main(String[] args){
// ImplementPayOff implementPayOff = new ImplementLoadingPayOff();
// AbstractionPayOff abstractionPayOff = new RefinedAbstraPayOff(implementPayOff);
// abstractionPayOff.PayOff();
ImplementPayOff implementPayOff = new ImplementLoadingPayOff();
AbstractionPayOff abstractionPayOff = new RefinedAbstraPayOff(implementPayOff);
abstractionPayOff.noPayOff();
}
}
优缺点
抽象和实现分离
这是桥梁模式的主要特点,它完全是为了解决继承的缺点而提出的设计模式。在该模式下,实现可以不受抽象的约束,不用再绑定在一个固定的抽象层次上。
优秀的扩展能力
实现细节对客户透明,客户不用关心细节的实现,它已经由抽象层通过聚合关系完成了封装。
不希望或不适用使用继承的场景
接口或抽象类不稳定的场景
实现细节对客户透明
客户不用关心细节的实现,它已经由抽象层通过聚合关系完成了封装。
桥梁模式的注意事项:
使用桥梁模式时主要考虑如何拆分抽象和实现,并不是一涉及继承就要考虑使用该模式,那还要继承干什么。
桥梁模式的意图还是对变化的封装,尽量把可能变化的因素封装到最细、最小的逻辑单元中,避免风险扩散。
系统设计时,发现类的继承有N层时,可以考虑使用桥梁模式。