Java设计模式之桥接模式
桥接(Bridge)模式的定义如下:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
假如你有一个几何形状(Shape)类, 从它能扩展出两个子类: 圆形(Circle)和方形(Square)。你希望对这样的类层次结构进行扩展以使其包含颜色, 所以你打算创建名为红色(Red)和蓝色(Blue)的形状子类。但是,由于你已有两个子类,所以总共需要创建四个类才能覆盖所有组合,例如蓝色圆形(BlueCircle)和红色方形(RedSquare)。
在层次结构中新增形状和颜色将导致代码复杂程度指数增长。例如添加三角形状,你需要新增两个子类,也就是每种颜色一个;此后新增一种新颜色需要新增三个子类,即每种形状一个。如此以往,情况会越来越糟糕。
优点
- 抽象与实现分离,扩展能力强
- 符合开闭原则
- 符合合成复用原则
- 其实现细节对客户透明
缺点
由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,能正确地识别出系统中两个独立变化的维度,这增加了系统的理解与设计难度。
结构
桥接(Bridge)模式包含以下主要角色。
抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。提供高层控制逻辑, 依赖于完成底层实际工作的实现对象。
扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。
客户端(Client):仅关心如何与抽象部分合作。但是,客户端需要将抽象对象与一个实现对象连接起来。
适用场景
当一个对象有多个变化因素的时候,考虑依赖于抽象的实现,而不是具体的实现。如手机品牌有2种变化因素,一个是品牌,一个是功能。
当多个变化因素在多个对象间共享时,考虑将这部分变化的部分抽象出来再聚合/合成进来,如通讯录和游戏,其实是可以共享的。
当我们考虑一个对象的多个变化因素可以动态变化的时候,考虑使用桥接模式,如上面例子中的手机品牌是变化的,手机的功能也是变化的,所以将他们分离出来,独立的变化。
实现
明确类中独立的维度。独立的概念可能是:抽象/平台,域/基础设施,前端/后端或接口/实现。
了解客户端的业务需求,并在抽象基类中定义它们。
确定在所有平台上都可执行的业务。并在通用实现接口中声明抽象部分所需的业务。
为你域内的所有平台创建实现类,但需确保它们遵循实现部分的接口。
在抽象类中添加指向实现类型的引用成员变量。抽象部分会将大部分工作委派给该成员变量所指向的实现对象。
如果你的高层逻辑有多个变体,则可通过扩展抽象基类为个变体创建一个精确抽象。
客户端代码必须将实现对象传递给抽象部分的构造函数才能使其能够相互关联。此后,客户端只需与抽象对象进行交互,无需和实现对象打交道
[实验任务一]:两个维度的桥接模式
用桥接模式实现在路上开车这个问题,其中,车可以是car或bus,路可以是水泥路或沥青路。
public class Bus implements Vehicle { @Override public void drive() { System.out.print("大巴"); } } public class Car implements Vehicle { @Override public void drive() { System.out.print("小轿车"); } } public class CementRoad extends Road { public CementRoad(Vehicle vehicle) { super(vehicle); } @Override public void driveOnRoad() { super.vehicle.drive(); System.out.println("行驶在水泥路"); } } public class main { public static void main(String[] args) { Road road = new CementRoad(new Car()); road.driveOnRoad(); } } public abstract class Road { protected Vehicle vehicle; public Road(Vehicle vehicle) { this.vehicle = vehicle; } public abstract void driveOnRoad(); } public class UnpavedRoad extends Road { public UnpavedRoad(Vehicle vehicle) { super(vehicle); } @Override public void driveOnRoad() { super.vehicle.drive(); System.out.println("行驶在沥青路"); } } public interface Vehicle { public void drive(); }