一、桥接模式概述
在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。
在提出桥接模式的时候指出,桥接模式的用意是"将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化"。这句话有三个关键词,也就是抽象化、实现化和脱耦。
桥接模式适用于:1、你不希望在抽象和他的实现之间有一个固定的绑定关系;2、类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充;3、对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译;4、你想对客户完全隐藏抽象的实现部分;5、你想在多个对象之间共享实现,但同时要求客户并不知道这一点。
桥接模式的类图如下:
可以看出,这个系统含有两个等级结构,也就是:由抽象化角色和修正抽象化角色组成的抽象化等级结构和由实现化角色和两个具体实现化角色所组成的实现化等级结构。
桥梁模式所涉及的角色有:
抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
具体实现化(Concrete Implementor)角色:这个角色给出实现化角色接口的具体实现。
二 、JDK中的桥接模式
桥接模式的意图是将抽象部分与它的实现部分分离,使它们都可以独立地变化。。JDK中使用桥接模式的例子有很多,因为java是跨平台的,为了更好的实现跨平台,桥接模式在jdk中很常见,比如java.awt.Button,按钮显示成什么样子(抽象部分)根据运行的系统来决定,点击按钮的行为(实现部分)由程序员自己写代码决定。它们均可以独立变化。
再举一个桥接模式的例子,这个例子来自http://blog.csdn.net/sunxing007/article/details/5448655,
举得例子是jdbc,类图如下:
jdbc为所有的数据库提供通用的接口, 一个应用系统可以根据需要选择合适的驱动程序, 通过驱动程序向数据库发送指令. 这个过程就是抽象角色把行为委托给实现角色的过程. 则应用程序和具体的驱动程序都可以独立变化。
三 、关于桥接模式的思考:
个人觉得桥接模式比较重要,所以在这里我还要加一个实现了的例子。
public abstract class Drawing {
public abstract void drawLine();
public abstract void drawCircle();
}
public class DP1 {
public static void draw_a_line(){
System.out.println("使用DP1的draw_a_line()画线");
}
public static void draw_a_circle(){
System.out.println("使用DP1的draw_a_circle()画圆");
}
}
public class DP2 {
public static void drawLine() {
System.out.println("使用DP2的drawLine()画线");
}
public static void drawCircle() {
System.out.println("使用DP2的drawCircle()画圆");
}
}
public class V1Drawing extends Drawing {
public void drawCircle() {
DP1.draw_a_circle();
}
public void drawLine() {
DP1.draw_a_line();
}
}
public class V2Drawing extends Drawing {
public void drawLine(){
DP2.drawLine();
}
public void drawCircle(){
DP2.drawCircle();
}
}
public abstract class Shape {
protected Drawing myDrawing;
abstract public void draw();
Shape(Drawing drawing) {
myDrawing = drawing;
}
protected void drawLine() {
myDrawing.drawLine();
}
protected void drawCircle() {
myDrawing.drawCircle();
}
}
public class Rectangle extends Shape {
Rectangle(Drawing drawing) {
super(drawing);
}
public void draw() {
drawLine();
drawLine();
drawLine();
drawLine();
}
}
public class Circle extends Shape {
Circle(Drawing drawing) {
super(drawing);
}
public void draw() {
myDrawing.drawCircle();
}
}
public class BridgeClient {
public static void main(String[] args) {
Drawing draw1 = new V1Drawing();
Drawing draw2 = new V2Drawing();
Shape shape1 = new Rectangle(draw1);
shape1.draw();
Shape shape2 = new Circle(draw2);
shape2.draw();
}
}
在这个例子中Shape对象实际上是一个Retangle或Circle对象,但Client并不知道到底是那个,因为它们看起来都一样。Drawing实际上是一个V1Drawing或V2Drawing,但Shape对象并知道到底是哪个,因为它们看起来都一样。DP1或DP2使用它的Drawing对象知道是哪一个。Shape是事物的抽象,Drawing是实现或者操作事物方法的抽象。他们两个都可以独立地变化。正如例子中所说那样,我们可以输出一个矩形可以使用V1Drawing也可以使用V2Drawing来完成,输出一个圆形也是一样都有两种方法。Bridge模式遵循了设计模式中两条基本策略:找出变化并封装之和优先使用对象聚集,而不是类继承。
小结:Bridge模式是一种抽象与其实现相分离的模式。它主要应用于:当事物是一组变化量,和对这些事物的操作方法(实现)也是一组变化量的情况,也就是说它们都是多变的。