桥接模式是将抽象部分与它的实现部分分离,使它们均可以独立地变化。它是一种对象结构型模式,又称为柄体[Handle and Body]模式或接口[Interfce]模式。 java
听懂了这句话就不用往下看了,说明你会了。设计模式
听不懂我以为也正常,若是用一句话能学会就没人看书了。像我这种笨人,都是学会了一个模式,而后往它的定义上套。函数
上面的概念中说到,抽象部分与它的实现(功能)部分分离,使它们均可以独立地变化。看下面这句话:测试
类的层级结构只有一层,功能层次结构与实现层级结构是混杂在一个层级结构中时,你可使用桥接模式。 —— 《图解设计模式》this
在说以前先说三个概念:spa
可能名词比较陌生,我刚看的时候以为好高大上啊,没听过的技术名词都以为高大上。设计
但这三个名词用白话来描述就特别简单。3d
用一句话就能说明白。code
类的层级结构就是类与子类之间的继承的层数。对象
这个图中类的层级结构的层数是:1
这个图中类的层级结构的层数是:2
类的层级结构的层数不能太深。
类的功能层次结构,用一句话说不完,得两句话。
首先两个类有继承关系。
父类具备一些基本功能,在子类中添加了新的功能,这就叫功能层次结构。
仍是不太好理解,我当时是这么理解的,子类继承了父类的方法以外,还有本身的方法,这种层次结构叫功能层次结构。例以下面的图:
动物定义了呼吸方法,而后狗继承了动物,狗还加了一个犬吠方法,这种层次结构就叫功能层次结构。
类的实现层次结构,也得用两句话说明。
首先两个类也有继承关系。
父类经过抽象的方式来定义方法。而后子类经过实现父类的抽象方法来完成这个方法的具体实现。
简单说就是一个类实现了父类的抽象方法。
动物定义了一个移动的抽象方法,狗实现了这个抽象方法,这种层次结构就叫实现层次结构。
类的层级结构只有一层,功能层次结构与实现层级结构混杂在一个层级结构中,这样很容易让类的设计变得复杂,也难以透彻地理解类的层次结构。由于本身也难以肯定究竟在类的哪个层次结构去增长新需求。
这个时候,能够尝试使用桥接模式,将抽象部分与它的实现部分分离,使它们均可以独立地变化。
简单说,就是怎么作抽象部分与它的实现部分分离。
下面会以一个场景来讲明,主要是两件事:
先看来图来讲明:
类图以奔驰车为例作了一个模型,奔驰的车有不一样的车系,每一个车系均可以远程开门,而车系下的各个车的协议解析都不一样。因此在车系中定义了远程开关车门的抽象方法。由各个开门协议对象去实现本身的协议解析。
这种方法目前看没有什么问题,可是设计原则也好,设计模式也好,或者说设计工做,一个很重要任务就是要考虑到将来的需求变动。
那么以这个图做为假设,需求变化成还有Benz的B、D、E系列的车,每一个下面有2个具体车型,那么咱们就要加入3个抽象类,6个实现类,就比如下面的类图:
就如上图所示。上面的场景,从类的实现层次结构来说,每次实现的增长都成倍的增长类,最后会出现类爆炸的场面。加一个车系和对应的车型,就须要对应数量的类,好比B、D、E系列的车,每一个下面有5个具体车型,那么咱们就要加入3 * 5 = 15个类。
相同的例子还有不少,好比有用画国画举例的,画国画须要毛笔,要用到小号、中号、大号的毛笔,另外还须要水彩(12颜色)。组合起来是:颜色数量 * 毛笔型号数量 = 12 * 3 = 36,须要36(红色小号、红色中号、红色大号,绿色小号 …… 黑色大号)个类。
若是需求变动了,增长了2种毛笔的型号,颜色也增长了12种,那么本次新增的类就是2 * 24 = 48,一共须要5 * 24 = 120,共须要120个类,完成这个需求,这就是类爆炸!
其次,上面的场景,想要实现一些新的功能,难以决定加到哪一层级。
由于这种设计,把类的功能扩展和类的多态实现混到了一块儿。混到一块儿的后果就是维护起来比较模糊。
例如:某些车要加一些新的功能,好比所有开门、前排开门、后排开门,而后又要加一些的新的实现,好比所有开门协议,开前门协议,看后门协议。这样代码混到了一块儿,职责不清晰,具体如图:
图中A系列的车系下的全部车型都有开门功能,所有开门功能,而后A200能够只开前门,A300能够只开后门。
在这种结构下扩展,只能将开门协议和开门动做放到一个类中,定义模糊。这就是所说的难以扩展。
通过桥接模式重构,获得上面的类图,将协议与车型分开,经过聚合的方式将车型与协议联接在一块儿,起到的重点是,分开后更容易扩展。当要增长新功能时,在类的功能层次结构(左侧,车型侧)增长便可,没必要对类的实现层次结构(右侧,协议侧)进行修改。反之亦然。
上面的例子中,若是新增了A系列车的具体车型,不须要增长协议类,若是增长了开门协议,也不须要增长车型类(B型车,C型车……同A型车)。
上一小节说到的国画需求也是同样,左侧能够是毛笔和3中型号的毛笔类,右侧是水彩和12种颜色的水彩类,加起来是15个类,添加毛笔型号不须要增长颜色一侧的类,添加颜色也不须要增长毛笔一次的类。
测试Main方法,里面是桥接模式的使用方式
package cc.xuepeng; /** 输出: A系列开门协议解析。 奔驰-A100开门 A系列开门协议解析。 奔驰-A200开门 A系列开门协议解析。 奔驰-A100: 第1个门-开门。 奔驰-A100: 第2个门-开门。 奔驰-A100: 第3个门-开门。 奔驰-A100: 第4个门-开门。 */ public class Client { public static void main(String[] args) { BenzA benzA100 = new BenzA100(new ProtocolBenzA(), "奔驰-A100"); BenzA benzA200 = new BenzA200(new ProtocolBenzA(), "奔驰-A200"); benzA100.openDoor(); benzA200.openDoor(); ((BenzA100) benzA100).openAllDoor(); } }
具体代码
// A系列奔驰车,类的功能结构层次的父类 public class BenzA { protected Protocol protocol; protected String name; // 在构造函数中,将协议对象注入进来,这里就是所谓的桥,经过这个protocol对象,能够调用到协议的方法 public BenzA(Protocol protocol, String name) { this.protocol = protocol; this.name = name; } // 开车门时,先调用协议对象完成业务操做。 public void openDoor() { protocol.resolveOpenDoorProtocol(); System.out.println(name + "开门"); } } public class BenzA100 extends BenzA { public BenzA100(Protocol protocol, String name) { super(protocol, name); } // 若是有特定的方法,能够从功能结构层侧一侧直接扩展。 public void openAllDoor() { super.protocol.resolveOpenDoorProtocol(); for (int i = 1; i <= 4; i++) { System.out.println(super.name + ": 第" + i + "个门-开门。"); } } } public class BenzA200 extends BenzA { public BenzA200(Protocol protocol, String name) { super(protocol, name); } } // A系列车的协议解析类,类的实现层次结构的父类 public abstract class Protocol { public abstract void resolveOpenDoorProtocol(); } public class ProtocolBenzA extends Protocol { public void resolveOpenDoorProtocol() { System.out.println("A系列开门协议解析。"); } }
桥接模式,从代码编写的角度来看,就是把一个类结构拆分红了两个类结构,一边负责经过类的继承特定添加功能。另外一边编写这些功能的具体实现。而后经过成员变量将实现传给功能。这样在扩展功能时,实现侧不须要修改,变动实现时,功能侧不须要修改。
从设计角度来看,要求咱们设计时先从业务维度出发去思考,考虑后续需求变动是否会使类的结构变得更复杂。
若是业务复杂(类型的子类较多,实现功能也各有不一样),而且后续的变动或者新功能会很频繁,那么就考虑使用桥接模式,将类的功能层次与类的实现层次拆分开,而后以包含(Has a)的方式创建功能层次与实现层侧的关系,便可在后续有需求变动时获得如下几点好处:
以上就是我对桥接模式的一些理解,有不足之处请你们矫正,谢谢。