首页 > 编程笔记 > Java笔记 阅读:15

Java桥接模式详解(附带实例)

桥接模式属于经典的 GoF 设计模式,它的目标是把两个类体系分开,让它们能够各自演化,这两个体系可以称为抽象体系与实现体系。

桥接模式是想通过组合代替继承。如果不这样做,那就需要设立一个基类,并针对各种抽象方案与各种实现方案之间的每一种组合情况,都设计该基类的一个子类,运用了桥接之后,我们则可以设计两个不同的基类,让它们分别引领各种抽象方案与各种实现方案。这样的话,原来的整个大体系就变成了两个能够独立发展的小体系。

桥接模式会用到封装与聚合,而且可能会通过继承把不同的职责划分到不同的类里,例如,可以将体系内的各类所共有的功能留在基类,将每个类特有的功能放在子类。

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

每一种车辆都扩展 Vehicle 这个抽象类,并通过该类所封装的一些基本功能来运作。另外,Vehicle 抽象类为了实现这些基本功能,会通过 Engine 接口来利用发动机的相关能力,这个 Engine 接口就起到了桥接的作用。它把两个体系(也就是车辆体系与发动机体系)连了起来,让前者能够在后者的体系中任意选择一种实现方案(例如,DieselEngine 或 PetrolEngine),参见下图。


图 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 设计原则。实现体系能够单独接受测试,而且其中的各种实现类,也能够通过应用程序的主代码,与抽象体系中的相关类型方便地联系起来。

制作桥接模式的时候,应该提醒自己不要添加不必要的职责,而且应该从设计模式的角度,思考能够让两个类体系独立演化的各种解决方案。

相关文章