Java桥接模式详解(附带实例)
桥接模式属于经典的 GoF 设计模式,它的目标是把两个类体系分开,让它们能够各自演化,这两个体系可以称为抽象体系与实现体系。
桥接模式是想通过组合代替继承。如果不这样做,那就需要设立一个基类,并针对各种抽象方案与各种实现方案之间的每一种组合情况,都设计该基类的一个子类,运用了桥接之后,我们则可以设计两个不同的基类,让它们分别引领各种抽象方案与各种实现方案。这样的话,原来的整个大体系就变成了两个能够独立发展的小体系。
桥接模式会用到封装与聚合,而且可能会通过继承把不同的职责划分到不同的类里,例如,可以将体系内的各类所共有的功能留在基类,将每个类特有的功能放在子类。
java.util.logging 包中的 Logger 类就用到了桥接模式。这个包位于 java.logging 模块中。Logger 类通过 Filter 接口的某个实现类,来过滤日志记录,以决定是应该发布还是应该屏蔽这条记录。这样设计,能够让负责记录的 Logger 体系与能够精准过滤日志内容的 Filter 体系各自演化,后者可以实现比前者提供的几种标准日志级别更为精细的控制。
【实例】用桥接模式将车辆类型与发动机类型隔开,令二者各自演化,使得每一种车都能够方便地选配各种发动机。

图 1 用UML类图演示Engine接口如何充当桥梁,令各种车辆都能任意选配某一款发动机
这些发动机的运作方式本身各有区别,但桥接模式使得 Vehicle 与 Engine 体系能够分别演化,而不用担心会影响对方(参见下面的实例)。
【实例】每一款具体的发动机都有特定的实现方式,但这并不影响各种车辆选配这些发动机。
该模式通过职责划分与封装,促使我们遵守 SOLID 设计原则。实现体系能够单独接受测试,而且其中的各种实现类,也能够通过应用程序的主代码,与抽象体系中的相关类型方便地联系起来。
制作桥接模式的时候,应该提醒自己不要添加不必要的职责,而且应该从设计模式的角度,思考能够让两个类体系独立演化的各种解决方案。
桥接模式是想通过组合代替继承。如果不这样做,那就需要设立一个基类,并针对各种抽象方案与各种实现方案之间的每一种组合情况,都设计该基类的一个子类,运用了桥接之后,我们则可以设计两个不同的基类,让它们分别引领各种抽象方案与各种实现方案。这样的话,原来的整个大体系就变成了两个能够独立发展的小体系。
桥接模式会用到封装与聚合,而且可能会通过继承把不同的职责划分到不同的类里,例如,可以将体系内的各类所共有的功能留在基类,将每个类特有的功能放在子类。
java.util.logging 包中的 Logger 类就用到了桥接模式。这个包位于 java.logging 模块中。Logger 类通过 Filter 接口的某个实现类,来过滤日志记录,以决定是应该发布还是应该屏蔽这条记录。这样设计,能够让负责记录的 Logger 体系与能够精准过滤日志内容的 Filter 体系各自演化,后者可以实现比前者提供的几种标准日志级别更为精细的控制。
Java桥接模式实例
现在举一个例子,假设我们想让车辆的类型与发动机的类型能够各自演化,例如,车辆可以有跑车(sport car)与轻型卡车(pickup,皮卡),发动机可以有汽油发动机(petrol engine)与柴油发动机(diesel engine)。每一种车辆都可以选用某一款发动机,为此,我们将车辆与发动机分别抽象成 Vehicle 与 Engine。我们的实例代码会演示怎样组合这两个体系,以创建出采用某种发动机的车辆,并执行车辆的 drive() 与 stop() 方法。【实例】用桥接模式将车辆类型与发动机类型隔开,令二者各自演化,使得每一种车都能够方便地选配各种发动机。
public static void main(String[] args) { System.out.println("Pattern Bridge, vehicle engines..."); Vehicle sportVehicle = new SportVehicle(new PetrolEngine(), 911); Vehicle pickupVehicle = new PickupVehicle(new DieselEngine(), 300); sportVehicle.drive(); sportVehicle.stop(); pickupVehicle.drive(); pickupVehicle.stop(); }输出结果如下:
Pattern Bridge, vehicle engines...
SportVehicle, starting engine
PetrolEngine, on
SportVehicle, engine started, hp:911
SportVehicle, stopping engine
PetrolEngine, self check
PetrolEngine, off
SportVehicle, engine stopped
PickupVehicle, starting engine
DieselEngine, on
PickupVehicle, engine started, hp:300
PickupVehicle, stopping engine
DieselEngine, off
PickupVehicle, engine stopped

图 1 用UML类图演示Engine接口如何充当桥梁,令各种车辆都能任意选配某一款发动机
这些发动机的运作方式本身各有区别,但桥接模式使得 Vehicle 与 Engine 体系能够分别演化,而不用担心会影响对方(参见下面的实例)。
【实例】每一款具体的发动机都有特定的实现方式,但这并不影响各种车辆选配这些发动机。
class DieselEngine implements Engine { ... @Override public void turnOff() { ... } } class PetrolEngine implements Engine { ... @Override public void turnOff() { selfCheck(); ... } private void selfCheck() { ... } }抽象体系中的 Vehicle 类只依赖实现体系中的 Engine 接口,而不依赖该接口的具体实现类。因此,实现体系里面的各种发动机都能够自行演化,而不用担心这会影响到抽象体系中的各种车辆。车辆只依赖发动机接口,而不依赖具体的发动机类。
总结
如果想降低某一系列的源代码,对具体实现类的依赖程度,那么桥接模式是个很好的方案。用了桥接模式之后,我们就不用过早地指定具体的实现类,而是可以推迟到程序真正需要用到实现类的那一刻。该模式通过职责划分与封装,促使我们遵守 SOLID 设计原则。实现体系能够单独接受测试,而且其中的各种实现类,也能够通过应用程序的主代码,与抽象体系中的相关类型方便地联系起来。
制作桥接模式的时候,应该提醒自己不要添加不必要的职责,而且应该从设计模式的角度,思考能够让两个类体系独立演化的各种解决方案。