一、定义
GOF上对桥接模式的意图描述:将抽象部分与它的实现部分分离,使得它们都可以独立的变化。
其实这么描述比较模糊,要将抽象部分与实现部分分离,直接使用继承:顶层的抽象类定义出各种抽象方法,子类给出抽象方法的不同实现。这样也可以达到抽象的目的。但是这样做将抽象层和实现部分固定在一起,使得难以对抽象部分和实现部分独立地改。
这时,可以利用组合将实现模块和对抽象部分调用的模块分割到不同的类体系中,将实现部分抽象出接口,组合到接口调用模块中。这样实现部分可以和调用部分分开演进,达到解耦合的目的。
二、应用场景
考虑驱动程序的使用。驱动程序通常按照定义好的接口操作计算机系统或者外围设备。每个驱动程序可能是Adapter 模式的例子,它使用其他类提供服务来实现目标接口。但是使用驱动程序的应用程序,则是一个抽象,他的结果取决于它使用的是哪一个驱动程序。使用驱动程序的应用程序是桥接模式的例子,它所依赖的底层方法在驱动程序中实现。
三、类图
四、代码示例
Window 抽象类
public abstract class Window {
private WindowImpl impl=null;
public Window(WindowImpl imp)
{
this.impl=imp;
}
public Window(){}
public WindowImpl getWindowImpl()
{
return this.impl;
}
abstract protected String DrawText();
abstract protected String DrawRect();
}
ApplicationWindow——Window的一个子类
public class ApplicationWindow extends Window {
ApplicationWindow(WindowImpl impl)
{
super(impl);
}
@Override
protected String DrawText() {
// TODO Auto-generated method stub
String str=getWindowImpl().DevDrawText()+" in ApplicationWindow";
return str;
}
@Override
protected String DrawRect() {
// TODO Auto-generated method stub
String str=getWindowImpl().DevDrawLine()+" in ApplictionWindow";
return str;
}
}
IconWindow——Window的另一个子类
public class IconWindow extends Window {
public IconWindow(WindowImpl impl)
{
super(impl);
}
@Override
protected String DrawText() {
// TODO Auto-generated method stub
String str=getWindowImpl().DevDrawText()+" in IconWindow";
return str;
}
@Override
protected String DrawRect() {
// TODO Auto-generated method stub
String str=getWindowImpl().DevDrawLine()+" in IconWindow";
return str;
}
}
WindowImpl 接口——实现的抽象接口
public interface WindowImpl {
String DevDrawText();
String DevDrawLine();
}
PMWindowImpl——一种WindowImpl的实现,即抽象的一种实现方式。
public class PMWindowImpl implements WindowImpl {
@Override
public String DevDrawText() {
// TODO Auto-generated method stub
return "DrawText based on PMWindow";
}
@Override
public String DevDrawLine() {
// TODO Auto-generated method stub
return "DrawLine based on PMWindow";
}
}
XWindowImpl——另一种WindowImpl的实现,即抽象的另一种实现方式
public class XWindowImpl implements WindowImpl {
@Override
public String DevDrawText() {
// TODO Auto-generated method stub
return "DrawText based on XWindow";
}
@Override
public String DevDrawLine() {
// TODO Auto-generated method stub
return "DrawLine based on XWindow";
}
}
客户端
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
WindowImpl ximpl=new XWindowImpl();
WindowImpl pmimpl=new PMWindowImpl();
Window window=new ApplicationWindow(ximpl);
System.out.println(window.DrawRect()+"-----------"+window.DrawText());
window=new ApplicationWindow(pmimpl);
System.out.println(window.DrawRect()+"-----------"+window.DrawText());
window=new IconWindow(ximpl);
System.out.println(window.DrawRect()+"-----------"+window.DrawText());
window=new IconWindow(pmimpl);
System.out.println(window.DrawRect()+"-----------"+window.DrawText());
}
}
运行结果:
DrawLine based on XWindow in ApplictionWindow-----------DrawText based on XWindow in ApplicationWindow
DrawLine based on PMWindow in ApplictionWindow-----------DrawText based on PMWindow in ApplicationWindow
DrawLine based on XWindow in IconWindow-----------DrawText based on XWindow in IconWindow
DrawLine based on PMWindow in IconWindow-----------DrawText based on PMWindow in IconWindow
利用桥接模式,将实现部分和对抽象接口的调用独立起来,这样实现部分可以独立演进。例如,在WindowImpl那条继承层次中加一个YWindowImpl类,用来实现YWindow风格的窗口。Window这边的继承层次不用产生变动。同样的,在Window继承层次中加一个ErrorWindow类,用于表示程序出错时弹出的窗口, WindowImpl那边的继承层次也不用发生变化。
五、适配器模式与桥接模式
学习桥接模式时,觉得桥接模式和对象适配器模式很相似。两者都是利用组合来使不同的对象相互协作,但是两者的设计意图是不同的。
Adapter模式用来帮助无关的类协同工作,使原本不兼容的接口可以满足新的需求。它通常在系统设计完成后才会被使用。然而,Bridge模式则是在系统设计刚开始时就被使用,它使得抽象接口和实现部分可以独立地进行改变。
我找到一篇具体描述这两个模式的区别及如何搭配协作的博文,有兴趣地可以看接下来的转载。