前言
桥接(Bridge)模式是属于结构型设计模式的一种,它是将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现的,从而降低了抽象和实现这两个可变维度的耦合度。
桥接模式适用于有多种维度变化的对象,比如说:汽车,汽车从类型划分有轿车、suv、越野车、卡车等等。从颜色划分有红色、白色、黑色等等。从品牌划分就更多了。在软件系统里,设计这种可多维度变化、组合的对象类。就需要用到桥接模式。
一、桥接模式
桥接(Bridge)模式包含以下主要角色。
- 抽象化(Abstraction)角色:定义抽象类或者接口,并持有一个实现化对象的引用。
- 抽象化实现(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
- 实现化(Implementor)角色:定义实现化角色的接口,供抽象实现角色调用。
- 具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。
接着以上面汽车维度划分为例,讲解一下桥接模式和普通逻辑的区别。
普通逻辑:假设只给汽车简单划分2个维度:类型和颜色。类型分别有轿车、卡车、suv。颜色分别有黑色、白色、蓝色。普通逻辑下如何设计这个汽车呢?
首先定义一个car的接口,有三个实现类:分别是轿车car、卡车car、suv-car。(这里先把类型维度体现出来),还有个颜色维度呢?每个类型的汽车都要有其相应的颜色。那只能分别为三个类型的car分别声明3种颜色的类型+颜色car的子类。这样继承下来的话,子类的个数就有9个。而当我们想新增一种颜色的car时,轿车、卡车、suv就要分别新增一个子类相对应。这种模式下子类的个数将会是两个维度的积。假如要新增第三个维度呢,要加一个汽车品牌的维度。那子类就是成倍的增长。显然,处理这种多维度的对象的情况,这种会增多类的数量,增大系统开销的方式是不行的。
桥接模式:回到桥接模式当中,上面介绍了桥接模式是将抽象与实现分离,使他们可以自由变化,正好就适用当前场景。(先来理解一下这里的抽象和实现。拿汽车类型和颜色举例。这里的汽车类型就是抽象、颜色就是实现。我抽象了三种类型的汽车。他们分别有对应三种颜色的实现。我想买一台小轿车,小轿车是抽象的。4S店里分别有黑色、白色、蓝色的小轿车,问我要哪台。XX颜色的小轿车是实现。) 理解了抽象和实现,桥接模式是如何把抽象和实现分离做到其各自自由变化呢?
首先定义汽车类型的抽象类或者接口类。三种类型的汽车,声明三个实现汽车类型抽象类的子类(同样先把汽车类型维度体现出来),那颜色维度如何体现呢?
上面把抽象层的类定义好了,接下来定义实现层的接口,颜色color抽象类或者接口。黑白蓝三种颜色的汽车,声明三个实现汽车颜色抽象类的子类。(颜色维度体现)
区别就在于颜色维度的体现,传统模式是直接给三个汽车类型子类声明XX个颜色的实现子类。而桥接模式则是通过组合复用替代继承复用。通过汽车类型的抽象类(抽象层)持有汽车颜色的抽象类或接口类(实现层)的引用。汽车类型抽象类引用汽车颜色抽象类后,二者就关联起来了。就可以自由组合了。两种维度下桥接模式只产生了6个子类(三个类型三个颜色)。因为二者组合复用关联在一起。当需要新增另外一种颜色时,只需要为新颜色实现一个color接口。使用时传递给汽车类型类就可以(因为汽车类型类持有汽车颜色类的引用)。比起传统模式新增一个颜色要增加的类数量大大减少。
而如果要新增一个汽车品牌维度的话,只需要在抽象层加一个品牌实现层的引用,跟颜色实现层引用是一样的原理。
使用桥接模式最重要的就是要能区分抽象和实现。理解维度之间的主次关系
二、桥接模式使用
代码演示:以上面汽车为例,分别建立抽象层、实现层类。以及它们相应的实现类
抽象层:
package com.example.study.bridge;
public abstract class AbstractCar {
protected Color color;
public AbstractCar(Color color) {
this.color = color;
}
abstract void carType();
}
抽象层实现类:
package com.example.study.bridge;
//轿车
public class JIaoCheCar extends AbstractCar{
public JIaoCheCar(Color color) {
super(color);
}
@Override
void carType() {
color.carColor();
System.out.println("小轿车");
}
}
package com.example.study.bridge;
//卡车
public class KaCheCar extends AbstractCar{
public KaCheCar(Color color) {
super(color);
}
@Override
void carType() {
color.carColor();
System.out.println("卡车");
}
}
package com.example.study.bridge;
//suv
public class SuvCar extends AbstractCar{
public SuvCar(Color color) {
super(color);
}
@Override
void carType() {
color.carColor();
System.out.println("suv");
}
}
实现层:
package com.example.study.bridge;
public interface Color {
void carColor();
}
实现层实现类
package com.example.study.bridge;
//黑色
public class Black implements Color{
@Override
public void carColor() {
System.out.println("黑色");
}
}
package com.example.study.bridge;
//白色
public class White implements Color{
@Override
public void carColor() {
System.out.println("白色");
}
}
package com.example.study.bridge;
//蓝色
public class Blue implements Color{
@Override
public void carColor() {
System.out.println("蓝色");
}
}
测试类:
package com.example.study.bridge;
public class Client {
public static void main(String[] args) {
//黑色轿车
Color black = new Black();
AbstractCar jiaoche = new JIaoCheCar(black);
jiaoche.carType();
//黑色卡车
AbstractCar kache = new KaCheCar(black);
kache.carType();
//黑色suc
AbstractCar suc = new SuvCar(black);
kache.carType();
//其他颜色同理,自由组合即可。汽车类型可随意变化、汽车颜色也可随意变化
}
}
package com.example.study.bridge;
//新增面包车类型
public class MIanBaoCar extends AbstractCar{
public MIanBaoCar(Color color) {
super(color);
}
@Override
void carType() {
color.carColor();
System.out.println("面包车");
}
}
package com.example.study.bridge;
//新增红颜色
public class Red implements Color{
@Override
public void carColor() {
System.out.println("红色");
}
}
现需要一台红色的suv以及白色的面包车(测试)
package com.example.study.bridge;
public class Client {
public static void main(String[] args) {
Color red = new Red();
AbstractCar mianbao = new MIanBaoCar(red);
mianbao.carType();
Color white = new White();
AbstractCar suv = new SuvCar(white);
suv.carType();
}
}
由此可见,在使用桥接模式后,汽车类型和汽车颜色维度就可自由变化,互不影响。不会造成大量子类创建。扩展起来也方便
总结
通过上面的讲解,我们能很好的感觉到桥接模式遵循了里氏替换原则和依赖倒置原则,最终实现了开闭原则,对修改关闭,对扩展开放。这里将桥接模式的优缺点总结如下。
桥接(Bridge)模式的优点是:
- 抽象与实现分离,扩展能力强
- 符合开闭原则
- 符合合成复用原则
- 其实现细节对客户透明
缺点是:由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,能正确地识别出系统中两个独立变化的维度,这增加了系统的理解与设计难度。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/99032.html