1 引言
生活中,很多东西存在多个维度上的变化,比如汽车,有颜色维度上的变化,车型维度上的变化,品牌维度上的变化,如何设计用最简单的方法来表示汽车的不同维度的变化了?可以用桥接模式。
2 定义
桥接模式,将抽象与实现分离,使其可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。桥接模式就是把继承关系改变为组合关系。
个人理解这个定义比较抽象(反正我第一次看的时候是没有明白的),延续引言中的例子,汽车就是一个高度抽象的产品,颜色与车型就是汽车的一个实现,我们在设计一款具体的汽车时,我们把实现好的车型与颜色拿过来直接放在汽车上,就能组成一辆汽车。
再举一个例子,如果你有3支不同笔尖的画笔,12种颜料,那么可以画出3 * 12种线条;而蜡笔想要做到同样的效果就需要36只。前面的画笔就是桥接模式(笔不同型号是一个变化维度,不同颜色的颜料是一个变化维度,两个维度不相互影响),而后面的画笔就是多重继承(笔型号和颜料一起影响蜡笔)。理解以后我们将其抽象成代码描述:pen类是一个抽象类,里面有一个方法draw()。我们想要使用画笔,则需要放入一种颜色,然后执行draw方法将这种颜色画出来。
3 结构是实现
桥接模式主要包含以下角色:
1.抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。比如汽车,包含一个对颜色与车型的引用。
2.实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。实现一个颜色。
3.具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。选择红色,黄色,白色。
4.扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。具体的汽车。
图片来自引用2
4 优缺点
桥接(Bridge)模式的优点是:
- 抽象与实现分离,扩展能力强
- 符合开闭原则
- 符合合成复用原则
缺点是:
- 由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,能正确地识别出系统中两个独立变化的维度,这增加了系统的理解与设计难度。
5 使用场景
桥接模式的一个常见使用场景就是替换继承。我们知道,继承拥有很多优点,比如,抽象、封装、多态等,父类封装共性,子类实现特性。继承可以很好的实现代码复用(封装)的功能,但这也是继承的一大缺点。
桥接模式通常适用于以下场景。
- 当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时。
- 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。
- 当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。
6 代码示例
延续汽车的例子,颜色与车型实现与车分开。
6.1 颜色工厂ColorFactory
/**
* @program: design-pattern-learning
* @author: zgr
* @create: 2021-11-01 14:55
**/
public class ColorFactory {
@AllArgsConstructor
public enum Color {
YELLOW(1, "yellow"),
RED(2, "red"),
WHITE(3, "white"),
BLACK(4, "black"),
GREEN(5, "green");
final int value;
final String desc;
}
public String getColor(int code){
String color = "";
switch (code){
case 1:
color = Color.YELLOW.desc;
break;
case 2:
color = Color.RED.desc;
break;
case 3:
color = Color.WHITE.desc;
break;
case 4:
color = Color.BLACK.desc;
break;
case 5:
color = Color.GREEN.desc;
break;
}
return color;
}
}
6.2 获取具体颜色 ConcreteColor
/**
* @program: design-pattern-learning
* @author: zgr
* @create: 2021-11-01 14:30
**/
public class ConcreteColor {
private ColorFactory colorFactory = new ColorFactory();
public String printColor(int code) {
return colorFactory.getColor(code);
}
}
6.3 车型工厂ModelFactory
/**
* @program: design-pattern-learning
* @author: zgr
* @create: 2021-11-01 14:55
**/
public class ModelFactory {
@AllArgsConstructor
public enum Model {
SUV(1, "越野车型"),
SEDAN(2, "轿车");
final int value;
final String desc;
}
public String getModel(int code){
String model = "";
switch (code){
case 1:
model = Model.SUV.desc;
break;
case 2:
model = Model.SEDAN.desc;
}
return model;
}
}
6.4 获取具体车型 ConcreteModel
/**
* @program: design-pattern-learning
* @author: zgr
* @create: 2021-11-01 14:30
**/
public class ConcreteModel {
private ModelFactory modelFactory = new ModelFactory();
public String printColor(int code) {
return modelFactory.getModel(code);
}
}
6.5 车抽象Car
/**
* @program: design-pattern-learning
* @author: zgr
* @create: 2021-11-01 14:26
**/
public interface Car {
/**
* 选择颜色
* @param code 颜色编号
*/
void setColor(int code);
/**
* 选择车型
* @param code 车型编号
*/
void setModel(int code);
}
6.6 特斯拉Tesla
/**
* @program: design-pattern-learning
* @author: zgr
* @create: 2021-11-01 15:05
**/
public class Tesla implements Car{
private ConcreteColor color = new ConcreteColor();
private ModelFactory modelFactory = new ModelFactory();
@Override
public void setColor(int code) {
System.out.println(color.printColor(code));
}
@Override
public void setModel(int code) {
System.out.println(modelFactory.getModel(code));
}
}
6.7 主函数
/**
* @program: design-pattern-learning
* @author: zgr
* @create: 2021-11-01 14:24
**/
public class MainClass {
public static void main(String[] args) {
Tesla teslaFactory = new Tesla();
System.out.println("配置颜色与车型:");
teslaFactory.setColor(3);
teslaFactory.setModel(2);
}
}
6.8 执行结果
7 引用
1.《大话设计模式》
8 源代码
https://github.com/airhonor/design-pattern-learning/tree/main/src/com/hz/design/pattern/bridge