设计模式:桥接模式

桥接模式是结构型模式,也是一个看定义什么的,看起来比较蒙的一个模式。
首先桥接模式有一个:

“Decouple an abstraction from its implementation so that the two can vary independently。”翻译成中文就是:“将抽象和实现解耦,让它们可以独立变化。”

这听起来好像懂了又不完全懂,咱们平时常见的桥接模式最佳实践:数据库连接池,还有一个sf4j日志。
数据库连接池,很常见,不同的数据库厂家的数据库连接信息是不同的,数据库连接池是一个具体的,但是对应的连接方法有很多,采用哪种连接池肯定不是简单的if else,实际上就是连接方法的抽象,各家连接方法发的实现。

sf4j日志的例子就更有意思,这是我看一个专栏,一个回复提到的,可以说桥接模式和sf4j说的非常明白:

多个纬度独立变化那个解释倒是比较容易理解。文中举的警报的例子很贴切。紧急程度和警报的方式可以是两个不同的纬度。可以有不同的组合方式。这与slf4j这一日志门面的设计有异曲同工之妙。slf4j其中有三个核心概念,logger,appender和encoder。分别指这个日志记录器负责哪个类的日志,日志打印到哪里以及日志打印的格式。三个纬度上可以有不同的实现,使用者可以在每一纬度上定义多个实现,配置文件中将各个纬度的某一个实现组合在一起就ok了。

一句话就是,桥接就是面向接口编程的集大成者。面向接口编程只是说在系统的某一个功能上将接口和实现解藕,而桥接是详细的分析系统功能,将各个独立的纬度都抽象出来,使用时按需组合

我这边的最简单的理解
一个类存在两个(或多个)独立变化的维度,我们通过组合的方式,让这两个(或多个)维度可以独立进行扩展。通过组合关系来替代继承关系,避免继承层次的指数级爆炸。

比如汽车具有多个维度:电动车燃油车,SUV还是MPV,货车还是客车等等,这要一个一个匹配222.。。。,真的会爆炸,干脆通过组合的方式来解耦。

桥接模式的组成:
上面都是一些形而上的,我们再看看桥接方式的组成,以下是我找到的一个UML图
在这里插入图片描述

抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
修正抽象化(RefinedAbstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
具体实现化(ConcreteImplementor)角色:这个角色给出实现化角色接口的具体实现。

再来个图帮助理解
在这里插入图片描述

下面我们知道桥接的组成可以通过代码来,一下我的gitlab的的demo演示
我的桥接代码演示地址

ps:我的例子有点问题,就是燃油车可以和suv这些组合子在一起,但是我这个构造函数是单独的,而不是组合方式直接添加进去,这个又要优化的,可以通过建造者builder方式来添加对应的属性。

抽象化(Abstraction)角色:Car汽车

package com.example.test.brige;

/**
 * @Author: zhangpeng
 * @Description:
 * @Date: 2022/6/9
 */
public abstract class Car {

    protected Ienergy ienergy;

    protected Itype itype;

    public abstract void call();

}

修正抽象化(RefinedAbstraction)角色:宝马汽车 比亚迪汽车

package com.example.test.brige;

/**
 * @Author: zhangpeng
 * @Description:
 * @Date: 2022/6/9
 */
public class BMWCar extends Car{

    public BMWCar(Ienergy ienergy){
        call();
       ienergy.energyType();
    }

    public BMWCar(Itype itype){
        call();
        itype.carType();
    }

    @Override
    public void call() {
        System.out.println("BMW");
    }
}

实现化(Implementor)角色:汽车的一些属性,比如是不是新能源还是燃油车,什么车型SUV还是MPV
(实际这些都在Car这个类里呢,毕竟是Car的属性)

   protected Ienergy ienergy;

    protected Itype itype;

具体实现化(ConcreteImplementor)角色:汽车的一些属性具体情况

package com.example.test.brige;

/**
 * @Author: zhangpeng
 * @Description:
 * @Date: 2022/6/9
 */
public class GasEnergy implements Ienergy{

    @Override
    public void energyType() {
        System.out.println("-------烧汽油的--------");
    }
}

桥接模式的优缺点:
优点:

  1. 分离抽象接口及其实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,也就是说抽象和实现不再在同一个继承层次结构中,而是“子类化”它们,使它们各自都具有自己的子类,以便任何组合子类,从而获得多维度组合对象。
  2. 在很多情况下,桥接模式可以取代多层继承方案,多层继承方案违背了“单一职责原则”,复用性较差,且类的个数非常多,桥接模式是比多层继承方案更好的解决方法,它极大减少了子类的个数。
  3. 桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合“开闭原则”。

缺点:

  1. 桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
  2. 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值