桥接模式

1. 背景

早期市场上的手机品牌都推出了不同外观的手机(旋转式/ 直立式/ 折叠式),按照传统的方式去模拟实现画出的类图式下面这样的
在这里插入图片描述
首先顶层有一个共同父类Phone定义了最顶层的方法,不同的样式去继承Phone,不同的品牌再去继承样式

加入我现在再新增一个新的样式,我就要让每个品牌的手机再去继承这个新的样式
在这里插入图片描述
这存在着扩展性问题(类爆炸): 如果我们新增手机的样式,就需要增加各个手机品牌的类,同样如果我们新增一个手机品牌,就要在各个样式类下面增加

违反了单一职责原则: 当我们新增了手机样式的时候,要同时增加所有品牌的手机,这样增加了代码维护成本

使用桥接模式解决

2. 定义与特点

定义:
将抽象与实现分离,把他们放在两个不同的类层次,使它们可以独立变化。
桥接模式基于类的最小设计原则(扩展功能时尽力增加少的类),它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度

优点:

  • 由于抽象与实现分离,所以扩展能力强;
  • 其实现细节对客户透明

缺点:
由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,这增加了系统的理解与设计难度

应用场景:

  • 当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时
  • 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时
  • 当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时

在这里插入图片描述
客户类: 桥接模式的调用者
抽象化角色: 定义抽象类,包含一个对实现化对象的引用(实际上是具体实现化角色),和Implementor是聚合的关系,也就是说抽象化角色就是桥,连接了抽象类和接口
扩展抽象化角色: 是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法
实现化角色: 定义实现化角色的接口,供扩展抽象化角色调用
具体实现化角色: 给出实现化角色接口的具体实现

从UML图可以看到,抽象类和接口时聚合的关系,也就是调用和被调用的关系

3. 桥接模式解决手机问题

在这里插入图片描述
Implementor 品牌接口Brand

public interface Brand {
    void call();
}

具体实现化角色 品牌的具体实现 – 小米

public class Mi implements Brand {
    public void call() {
        System.out.println("小米打电话");
    }
}

具体实现化角色 品牌的具体实现 – Vivo

public class Vivo implements Brand {
    public void call() {
        System.out.println("Vivo打电话");
    }
}

抽象化角色 抽象类Phone,里面有对具体品牌的引用

public abstract class Phone {
    //组合品牌
    protected Brand brand;

    public Phone(Brand brand) {
        this.brand = brand;
    }
    public void call(){
        this.brand.call();
    }
}

扩展抽象化角色 Phone的具体子类 – 折叠手机

public class FoldedPhone extends Phone{
    public FoldedPhone(Brand brand) {
        super(brand);
    }

    public void call(){
        System.out.println("我是折叠手机");
        super.call();
    }
}

扩展抽象化角色 Phone的具体子类 – 直板手机

public class UpRightPhone extends Phone {
    public UpRightPhone(Brand brand) {
        super(brand);
    }

    public void call(){
        System.out.println("我是直板机");
        super.call();
    }
}

可以看到我们在抽象化角色Phone中持有品牌,而我们扩展抽象化角色的call方法实际上调用的是具体实现化角色的call方法
使用

public class Client {
    public static void main(String[] args) {
        Phone phone = new FoldedPhone(new Mi());
        phone.call();
    }
}

4. 总结

我们再回到文初,想想我们到底遇到了什么问题
我们有ABC三种不同样式的手机以及abc三种不同品牌的手机,要表示所有的不同样式不同品牌的手机就有3X3=9种不同的组合方法
我们第一个想到的程序表示就是让a,b,c去继承A,B,C来表示这种组合关系
在这里插入图片描述
但是这样如果再新增样式D,就要让abc再去继承D产生新类十分麻烦

所以我们考虑能不能使用一个中间人,让中间人去维护样式和品牌的关系;答案是可以的,让样式的抽象类去持有品牌,而不是采用继承的关系,这样样式的具体实现类也就持有了品牌,新增品牌的时候只要给样式的具体实现类传入品牌就行了
在这里插入图片描述

5. 桥接模式模式的扩展

在软件开发中,有时桥接(Bridge)模式可与适配器模式联合使用。当桥接(Bridge)模式的实现化角色的接口与现有类的接口不一致时,可以在二者中间定义一个适配器将二者连接起来
在这里插入图片描述

6. JDBC中的桥接模式

使用JDBC获取Connection的时候,把不同数据库的驱动名称传入Class.forName() 这个方法就能正常使用数据库连接

try {
	Class.forName("com.mysql.jdbc.Driver");
    String url = "";
    String user = "";
    String password = "";
    Connection con = DriverManager.getConnection(url, user, password);
} catch (Exception e) {

}

这里就引入Java设计的桥接模式,基于Java支持多种数据库的操作,但是不同数据库的自我实现和传输协议都不尽相同,难道Java为每一种数据库写一种接口去支持数据库厂商的实现,显然违背了精简设计的原则,这里Java做的是提供一套接口让厂商自己实现,一套接口给程序开发者调用,两者的结合就是经典的桥接模式

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值