前言
在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。桥接模式在我们很多框架中都能看到,比如spring的JdbcTemplate
本节,我们就桥接模式,展开详细介绍。
1. 桥接模式中的角色
1.1 抽象化(Abstraction)角色:
定义抽象类,并包含一个对实现化对象的引用。
1.2 扩展抽象化(Refined Abstraction)角色:
抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
1.3 实现化(Implementor)角色:
定义实现化角色的接口,供扩展抽象化角色调用。
1.4 具体实现化(Concrete Implementor)角色:
给出实现化角色接口的具体实现。
2. 代码示例
本文以点咖啡为例,咖啡有大小杯,和加奶,加糖两个维度。
2.1 定义抽象化角色(咖啡)
package com.wanlong.design_pattern.structure.bridge;
/**
* @author wanlong
* @version 1.0
* @description: 抽象化角色,咖啡
* @date 2022/9/15 17:40
*/
public abstract class Coffee {
protected ICoffeeAdditives additives;
public Coffee(ICoffeeAdditives additives) {
this.additives = additives;
}
public abstract void orderCoffee(int count);
}
2.2 定义扩展抽象化角色
2.2.1 定义抽象化角色(大杯咖啡)
package com.wanlong.design_pattern.structure.bridge;
/**
* @author wanlong
* @version 1.0
* @description: 扩展抽象化角色(大杯咖啡)
* @date 2022/9/15 17:42
*/
public class LargeCoffee extends Coffee {
public LargeCoffee(ICoffeeAdditives additives) {
super(additives);
}
@Override
public void orderCoffee(int count) {
additives.addSomething();
System.out.println("大杯咖啡" + count + "杯");
}
}
2.2.1 定义抽象化角色(小杯咖啡)
package com.wanlong.design_pattern.structure.bridge;
/**
* @author wanlong
* @version 1.0
* @description: 扩展抽象化角色(小杯咖啡)
* @date 2022/9/15 17:42
*/
public class SmallCoffee extends Coffee {
public SmallCoffee(ICoffeeAdditives additives) {
super(additives);
}
@Override
public void orderCoffee(int count) {
//小杯咖啡,加东西
additives.addSomething();
System.out.println("小杯咖啡" + count + "杯");
}
}
2.3 定义实现化角色(加什么)
package com.wanlong.design_pattern.structure.bridge;
/**
* @Description:实现化角色,供扩展抽象化角色调用。
* @Author: wanlong
* @Date: 2023/5/14 12:47
**/
public interface ICoffeeAdditives {
void addSomething();
}
2.4 定义具体实现化角色(奶还是糖)
2.4.1 定义具体实现化角色(奶)
package com.wanlong.design_pattern.structure.bridge;
/**
* @author wanlong
* @version 1.0
* @description: 实现具体化角色
* @date 2022/9/15 17:41
*/
public class Milk implements ICoffeeAdditives {
@Override
public void addSomething() {
System.out.println("加奶");
}
}
2.4.2 定义具体实现化角色(糖)
package com.wanlong.design_pattern.structure.bridge;
/**
* @author wanlong
* @version 1.0
* @description: 具体实现化角色
* @date 2022/9/15 17:41
*/
public class Sugar implements ICoffeeAdditives {
@Override
public void addSomething() {
System.out.println("加糖");
}
}
2.5 客户端测试
@Test
public void testBridge() {
//点两杯加奶的大杯咖啡
LargeCoffee largeWithMilk = new LargeCoffee(new Milk());
largeWithMilk.orderCoffee(2);
System.out.println("============这是一条华丽的分割线==========");
//点三杯加糖的小杯咖啡
new SmallCoffee(new Sugar()).orderCoffee(3);
}
代码运行结果:
加奶
大杯咖啡2杯
============这是一条华丽的分割线==========
加糖
小杯咖啡3杯
后面需要加其他口味,只需要像牛奶和糖一样,新增具体实现类即可,客户端调用即可,不需要修改原来的类。
3. 总结
3.1 优缺点
3.1.1 优点
- 分离抽象与实现 : 分离抽象部分和具体实现部分 。
- 抽象和实现不在同一个继承层次中 , 可以动态的将抽象的子类对象和实现的子类对象进行组合 ,通过进行组合 , 可以获得多维度的组合对象 ;
- 提高扩展型 : 提高了系统的可扩展性 ;
- 解耦了抽象与实现 :桥接模式使用组合关系解耦了抽象和实现之间的继承关系 。抽象与实现二者可以沿着自己的维度继续自行进行扩展 , 不需要改变系统原有的功能 ;
- 符合开闭原则 ;
- 符合合成复用原则 ;
3.1.2 缺点
- 系统复杂 : 增加了 系统的 理解 与 设计难度 ;
- 识别变化维度 : 需要正确地 识别出 系统中 , 两个独立变化的 维度 ;
- 桥接模式的使用范围 , 有一定的局限性 ;
3.2 常用场景
- 抽象实现灵活 : 抽象和具体实现之间 , 需要增加更多灵活性的情况下 , 适合使用桥接模式 ;
- 独立变化维度 : 一个类存在两个或更多的独立变化维度 , 并且这些维度都需要 独立扩展 。抽象部分可以独立扩展 , 具体实现的部分 , 也可以独立扩展 ;
- 不使用继承 : 不希望使用继承 , 或 因多层继承导致系统类的个数增加 ;
- 使用桥接模式 , 可以 避免在这两个层次之间 , 建立静态的继承关系 , 通过 桥接模式 在二者之间建立 关联关系 ;
3.3 桥接模式和组合模式比较
- 组合模式更强调部分与整体间的组合
- 桥接模式 更强调平行级别上,不同类的组合
3.4 桥接模式和适配器模式比较
3.4.1 共同点
都是让两个类配合工作 ;
3.4.2 不同点
- 二者目的不同
- 适配器模式是改变已有接口,让二者之间相互配合,目的是配合 ;
- 桥接模式分离抽象和具体的实现 , 目的是分离。桥接模式最重要的是将抽象与实现解耦 , 通过组合在抽象与实现 之间搭建桥梁 ;
以上,本人菜鸟一枚,如有问题,请不吝指正。