桥接模式(Bridge Design Pattern),也叫作桥梁模式,是八种结构型模式之一。在 GoF 的《设计模式》一书中,桥接模式是这么定义的:“Decouple an abstraction from its implementation so that the two can vary independently。”翻译成中文就是:“将抽象和实现解耦,让它们可以独立变化”。
桥梁模式从名字来看很具象,但从定义来看又很抽象难懂。对于初学设计模式,桥梁最难理解的一种模式之一。
本文我们从一个飞机的例子慢慢演化,来理解桥梁模式。
- 按用途(维度一)区分,飞机可分为客运飞机、货运飞机、私人飞机。
//飞机
interface Aircraft {
public void purpose();
}
//客运飞机
class PassengerAircraft {
public void purpose(){
//运客
}
}
//货运飞机
class CargoAircraft {
public void purpose(){
//运货
}
}
//私人飞机
class PrivateAircraft {
public void purpose(){
//运私人
}
}
- 按动力(维度二)区分,飞机可分为螺旋桨飞机、喷气式飞机。
(为了图可以简单一些,省略了私人飞机的类图)
我们看到当抽象Aircraft扩展时(添加了动力power),实现类也要跟着扩展了(子类从原来三个变成了六个)。
可想如果再增加飞行速度(维度三)、其他(维度...),子类就会成指数增加了。而且只要扩展抽象,子类也要跟着扩展;修改抽象,也会影响到所有子类。
所以需要让抽象与实现进行解耦,让抽象和实现可以独立变化。如何做呢?如果你看过《多用组合少且继承的设计思想》会知道,桥接模式就是这种思想最直接的表现形式。
现在我们运用组合的方式来从头开始重构一下。
- 按用途(维度一)区分,飞机可分为客运飞机、货运飞机、私人飞机。
interface Purposeable {
public void purpose();
}
//货运
class Cargo implements Purposeable {
public void purpose(){
System.out.println("运货");
}
}
//客运
class Passenger implements Purposeable {
public void purpose(){
System.out.println("运客");
}
}
//飞机
abstract class Aircraft {
Purposeable purposeImpl;
public Aircraft(Purposeable purposeImpl) {
this.purposeImpl = purposeImpl;
}
public void purpose(){
this.purposeImpl.purpose();
}
}
//客运飞机
class PassengerAircraft {
public PassengerAircraft(){
super(new Passenger());
}
}
//货运飞机
class CargoAircraft {
public CargoAircraft(){
super(new Cargo());
}
}
public class Demo implements {
public static void main(String[] args) {
Aircraft passengerAircraft= new PassengerAircraft();
passengerAircraft.purpose();
Aircraft cargoAircraft= new CargoAircraft();
cargoAircraft.purpose();
}
}
//执行结果
运客
运货
重构之后,抽象接口Aircaft做成了抽象类,purpose的实现, 并不在抽象Aircaft中,而且与另一个抽象Purposeable进行组合,purpose的实现交由Purposeable的子类来实现。通过这种方式purpose可以做独立变化,跟Aircaft没有关系。现在抽象已经与实现进行的解耦,并且实现也可以独立变化,但是抽象如何独立变化呢?我们继续往下看。
- 按动力(维度二)区分,飞机可分为螺旋桨飞机、喷气式飞机。
interface Powerable {
public void power();
}
//喷气式
class Jet implements Powerable{
public void power(){
System.out.println("喷气");
}
}
//螺旋桨
class Propeller implements Powerable{
public void power(){
System.out.println("螺旋桨");
}
}
interface Purposeable {
public void purpose();
}
//货运
class Cargo implements Purposeable {
public void purpose(){
System.out.println("运货");
}
}
//客运
class Passenger implements Purposeable {
public void purpose(){
System.out.println("运客");
}
}
//飞机
abstract class Aircraft {
Purposeable purposeImpl;
Powerable powerImpl;
protected Aircraft(Purposeable purposeImpl){
this.purposeImpl= purposeImpl;
}
protected Aircraft(Purposeable purposeImpl, Powerable powerImpl){
this.purposeImpl= purposeImpl;
this.powerImpl = powerImpl;
}
public void purpose(){
this.purposeImpl.purpose();
}
public void power(){
this.powerImpl .power();
}
}
//客运飞机
class PassengerAircraft {
public PassengerAircraft(){
super(new Passenger());
}
public PassengerAircraft(Powerable powerImpl){
super(new Passenger(),powerImpl);
}
}
//货运飞机
class CargoAircraft {
public CargoAircraft(){
super(new Cargo());
}
public CargoAircraft(Powerable powerImpl){
super(new Cargo(),powerImpl);
}
}
public class Demo implements {
public static void main(String[] args) {
//螺旋桨客运飞机
Aircraft propellerPassengerAircraft= new PassengerAircraft(new Propeller());
propellerPassengerAircraft.purpose();
propellerPassengerAircraft.power();
//喷气客运飞机
Aircraft jetPassengerAircraft= new PassengerAircraft(new Jet());
jetPassengerAircraft.purpose();
jetPassengerAircraft.power();
//螺旋桨货运飞机
Aircraft propellerCargoAircraft= new CargoAircraft(new Propeller());
propellerCargoAircraft.purpose();
propellerCargoAircraft.power();
//喷气货运飞机
Aircraft jetCargoAircraft= new PassengerAircraft(new Jet());
jetCargoAircraft.purpose();
jetCargoAircraft.power();
}
}
//执行结果
运客
螺旋桨
运客
喷气
运货
螺旋桨
运货
喷气
我们看到虽然新加了Powerable维度,但是抽象Aircraft并没有新增新的子类,也就是Aircraft扩展了,子可以跟着扩展,只需要做很小的修改。而且因为并没有改变原有的属性和方法,所以对原先的调用者也不会有影响,满足开闭原则。现在抽象也可以独立变化了。
到现在桥梁模式已经学完了,你是否明白了怎么使用。
现在问题来了,为什么要叫桥梁模式呢?难道是类模型看起来像座桥吗?如果你知道,请你评论告诉我。