蜡笔和油画笔都是常见的画笔。假设画笔都有大中小三个尺寸,都有12个颜色。如果要准备蜡笔,那么就需要3*12 = 36个类。而如果要准备油画笔,那就只需要三只尺寸的笔和一个调色盘,只需要3+12 = 15个类。如果要增加一个尺寸,蜡笔就需要为每个颜色增加对应尺寸的笔,就是12支。而油画笔就只用增加一支笔。
用图表示蜡笔:
这是一种多层继承的结构,会导致扩展时要新增的类非常多。并且并不符合单一职责原则
而油画笔将两个属性抽离,形成两个独立的维度:
很明显,如果要用代码实现,油画笔的模式更简单。而这种模式就是桥接模式。
一、定义
桥接模式是一种结构型设计模式。
桥接模式:将抽象部分与它的实现部分解耦,使得两者都能够独立发生变化。
说人话就是,把他的属性和他的具体实现解耦。颜色是画笔的属性,尺寸是画笔的具体实现。解耦后任意一个维度发生变化都不会影响到另一个维度。
二、结构
桥接模式由4个角色组成:
-
Abstraction(抽象类):在前面的例子中,画笔就是一个抽象类。
-
RefinedAbstraction(扩展抽象类):他是抽象类的具体实现,比如油画笔。
-
Implementor(实现类接口):这是抽象部分,需要解耦出来的部分。在前面的例子中是颜色。
-
ConcreteImplementor(具体实现类):它是Implementor的具体实现类,比如红色。
三、代码实现
现设计一个画画软件。用户可以选择不同的画笔,有蜡笔和油画笔可选;用户也可以选择画笔的颜色。用桥接模式实现。
首先定义颜色的接口:
public interface Color {
void outputColor();
}
然后添加具体的颜色
public class Red implements Color{
@Override
public void outputColor() {
System.out.println("红色");
}
}
public class Blue implements Color{
@Override
public void outputColor() {
System.out.println("蓝色");
}
}
接着定义画笔的抽象类
public abstract class PaintBrush {
Color color;
public PaintBrush(Color color) {
this.color = color;
}
abstract void draw();
}
这里通过组合的方式,将颜色作为成员变量添加到了属性里。
再来实现两个具体的画笔
public class Crayon extends PaintBrush{
public Crayon(Color color) {
super(color);
}
@Override
void draw() {
System.out.println("用蜡笔画画");
}
}
public abstract class PaintBrush {
Color color;
public PaintBrush(Color color) {
this.color = color;
}
abstract void draw();
}
然后用户就可以使用了
public class Client {
public static void main(String[] args) {
Color color = new Red(); //选择颜色
PaintBrush paintBrush = new OilPaintBrush(color); // 选择画笔
color.outputColor();
paintBrush.draw();
}
}
运行结果:
此时如果要新增一个颜色,或新增一种画笔,就只需要添加一个类,并且无需修改原有的代码,符合开闭原则。
四、特点
-
桥接模式将抽象部分和实现部分解耦,极大的增强了系统的扩展性;并且取代了多层继承的方案,符合单一职责原则。
-
但桥接模式会增加系统设计和理解的难度,要求设计人员有较强的抽象能力。并且有一定的局限性,抽象部分和实现部分必须是两个独立的维度。
五、适用场景
以下场景适合适用桥接模式:
-
当系统内有多层继承关系的时候,考虑用桥接模式替换
-
当一个类存在两个(或多个)独立变化的维度,且这些维度都需要独立地进行扩展时,可以适用桥接模式。