设计模式太难学?Java设计模式之桥接模式


前言

桥接(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)模式的优点是:

  • 抽象与实现分离,扩展能力强
  • 符合开闭原则
  • 符合合成复用原则
  • 其实现细节对客户透明

缺点是:由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,能正确地识别出系统中两个独立变化的维度,这增加了系统的理解与设计难度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值