程序员小名去摆摊卖奶茶了,口味有香、甜。 型号有大、中、小。假如小名先在家里把这些奶茶装好,那么最少要装2x3 = 6杯奶茶,如果此时新增一个口味:酸,那么就需要多装3杯奶茶了。而且这样做,等客户买走一种,比如 甜+大杯后,这种型号就没有了,这样扩展性不太行哦。
换种方案:摆摊的时候只要带两样东西:1)不同口味的饮料;2)不同型号的杯子。 那么就可以不要先再家装好,客户想买什么,临时装好就行了,而且就算新增一个口味,那么也只是多准备一种饮料而已,而不是要增加三种类型。
第二种方案就算本文讲的桥接模式,“客户点奶茶口味及型号,小名临时装”的这个动作就是“桥”,将口味与杯子型号连接起来。
1 桥接模式概述
如果软件系统种某个类存在两个或以上变化的维度,通过该模式可以将这些维度分离处理,使两者可以独立扩展,让系统更加符合单一职责原则。将独立的维度设计为不同的继承等级接口,并在抽象层建立一个抽象关联,该关联类似一条连接这些独立继承结构的桥。
图 桥接模式结构图
Abstraction,抽象类,一般是抽象类而不是接口,既可包含抽象业务方法,也可以包含具体业务方法。做更多、更复杂的操作。定义了一个Implementor类型的对象并可维护该对象。
RefinedAbstraction,扩充抽象类,实现了在Abstraction中声名的抽象业务方法。可以调用在Implementor中定义的业务方法。
Implementor,实现类接口,接口不一定要与Abstraction的接口完全一致,仅提供基本操作。
ConcreteImplementor,具体实现类,实现Implementor基本操作接口。
public abstract class MilkTeaAbstraction {
protected CupImplementor cupImplementor;
public MilkTeaAbstraction(CupImplementor cupImplementor) {
this.cupImplementor = cupImplementor;
}
public abstract void taste(); //口味
}
public class FragrantMilkTea extends MilkTeaAbstraction{
public FragrantMilkTea(CupImplementor cupImplementor) {
super(cupImplementor);
}
@Override
public void taste() {
System.out.println("香 " + cupImplementor.model() + ";");
}
}
public class AcidMilkTea extends MilkTeaAbstraction{
public AcidMilkTea(CupImplementor cupImplementor) {
super(cupImplementor);
}
@Override
public void taste() {
System.out.println("酸 " + cupImplementor.model() + ";");
}
}
public interface CupImplementor {
String model(); //型号
}
public class BigCupImplementor implements CupImplementor{
@Override
public String model() {
return "大杯";
}
}
public class SmallCupImplement implements CupImplementor{
@Override
public String model() {
return "小杯";
}
}
public class Client {
public static void main(String[] args) {
CupImplementor cupImplementor = new BigCupImplementor();
MilkTeaAbstraction milkTeaAbstraction = new FragrantMilkTea(cupImplementor);
milkTeaAbstraction.taste();
// 运行结果:
// 香 大杯;
}
}
2 优缺点
优点:
- 用“对象间的关联关系”解耦抽象和实现之间固有的绑定关系,使得抽象和实现可沿着各自的维度来变化。即抽象和实现不再在同一个继承层次结构中。
- 提供了系统的可扩展性,在两个维度中任意扩展一个维度,都不需要修改原有系统,符合开闭原则。
缺点:
- 增加系统的理解和设计难度,要求开发者一开始就针对抽象层进行设计与编程。
- 要求正确识别出系统中两个独立变化的维度,如果识别这两个维度也需要一定的经验积累。
3 适用场景
- 一个类存在两个(或多个)独立变化的维度,且这些维度都需要独立进行扩展。
- 不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统。