桥梁模式的用意是:将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立的变化。
抽象化
存在于多个实体中的共同的概念性联系,就是抽象化。通常情况下,一组对象如果具有相同的概念性联系,那么它们就可以通过一个共同的类来描述。
实现化
抽象化给出的具体实现,就是实现化。
一个类的实例就是这个类的实现化,一个具体子类是它的抽象超类的实现化。
而在更加复杂的情况下,实现化也可以是与抽象化等级结构相平行的等级结构,
同样可以由抽象类和具体类组成。
脱耦
所谓耦合,就是两个实体的行为的某种强关联。
而将它们的强关联去掉,就是耦合的解耦,或称脱耦。
在这里,脱耦是指将抽象化和实现化之间的耦合解脱开,或者说将它们之间的强关联改换成弱关联。
所谓强关联,就是在编译时期已经确定的,无法在运行时期动态改变的关联;
所谓弱关联,就是可以动态的确定并且可以在运行时期动态的改变的关联。
在java语言中,继承关系是强关联,而聚合关系是弱关联。
在桥梁模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,
从而使两者可以相对独立的变化。这就是桥梁模式的用意
桥梁模式的结构
桥梁模式是对象的结构模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
这个系统含有两个等级结构:
- 由抽象化角色和修正抽象化角色组成的抽象化等级结构。
- 由实现化角色和两个具体实现化角色所组成的实现化等级结构。
桥梁模式所涉及的角色有:
- 抽象化角色(Abstraction): 抽象化给出的定义,并保存一个对实现化对象的引用。
- 修正抽象化角色(Refined Abstraction): 扩展抽象化角色,改变和修正父类对抽象化的定义。
- 实现化角色(Implementor): 这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
- 具体实现化角色(Concrete Implementor): 这个角色给出实现化角色接口的具体实现。
抽象化角色就像一个水杯的手柄,而实现化角色和具体实现化角色就像水杯的杯身。手柄控制杯身,这就是此模式别名柄体的来源。
源代码:
抽象化角色
代码语言:javascript复制public abstract class Abstraction {
protected Implementor imp;
//某个商业方法
public void operation(){
imp.operationImp();
}
}
这个实现是通过向实现化对象的委派(调用operationImp()方法)实现的。
修正抽象化角色
代码语言:javascript复制public class RefinedAbstraction extends Abstraction {
//某个商业方法在修正抽象化角色的实现
public void operation(){
//improve logic
}
}
实现化角色
代码语言:javascript复制public abstract class Implementor {
//某个商业方法的实现化声明
public abstract void operationImp();
}
具体实现化角色
代码语言:javascript复制public class ConcreteImplementor extends Implementor {
//某个商业方法的实现化实现
@Override
public void operationImp() {
System.out.println("Do something...");
}
}
一般而言,实现化角色中的每一个方法都应当有一个抽象化角色中的某一个方法与之相对应。
但是,反过来则不一定。也就是说,抽象化角色的接口比实现化角色的接口宽。
抽象化角色除了提供与实现化角色相关的方法之外,还有可能提供其他的商业方法;
而实现化角色则往往仅为实现抽象化角色的相关行为而存在。
关于桥梁模式的实现
实现化角色的退化
在只有一个具体实现化角色的情况下,抽象的实现化角色就变的没有意义了,不如取消。
抽象化角色的行为
在很多情况下,Abstraction与RefinedAbstraction并没有区别。
也就是说,修正抽象化角色没有修正抽象化角色的行为,这当然使允许出现的情况。
java中的AWT库中使用了桥梁角色将Component的等级结构与ComponentPeer的等级结构分割开,
Component的子类通过委派调用ComponentPeer中的功能。在这个例子中,Component的子类并没有修正Component的行为。
多个实现类的情况
当有多与一个实现类时,应该在什么地方,什么时候,怎么创建一个实现类的实例呢?
如果抽象化角色知道具体实现化角色的所有信息,那么它可以在构造函数里根据传进的参数
决定创建哪一个具体实现化角色类的实例。
共享具体实现化角色
可以有几个抽象化角色类合用相同的具体实现化角色类。
在什么情况下应当使用桥梁模式
- 如果一个系统需要在构建的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次直接建立静态的联系。
- 设计要求实现化角色的任何改变不应当影响客户端,或者说实现化角色的改变对客户端是完全透明的。
- 一个构件有多于一个的抽象化角色和实现化角色,系统需要它们之间进行动态耦合。
- 虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理者两者。
驱动器和JDBC驱动器
大多数的驱动器(Driver)都是桥梁模式的应用。
使用驱动程序的应用系统就是抽象化角色,而驱动器本身扮演实现化角色。
应用程序是建立在JDBC API的基础上的。