一,桥接模式定义
桥接模式将抽象部分与它的具体实现部分分离,使它们都可以独立地变化,属于结构型模式。桥接模式的核心在于解耦抽象和实现,基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。桥接模式主要目的是通过组合的方式建立两个类之间的联系,而不是继承。
二,使用场景
当一个类内部具备两种或多种变化维度时,桥接模式适用于以下几种业务场景:
- 在抽象和具体实现之间需要增加更多的灵活性的场景
- 一个类存在两个或多个独立变化的维度,而这两个或多个维度都需要独立进行扩展
- 不希望使用继承,或因为多层继承导致系统类的个数剧增
三,桥接模式的组成角色
抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
修正抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。
四,实例场景
一个咖啡店卖咖啡,卖出的咖啡可以从几个角度来看(即一个类内部具备两种或多种变化维度时):
1. 口味:摩卡、拿铁、美式等;
2. 容量:大杯、中杯、小杯等;
3. 添加物:牛奶、糖、蜂蜜等;
4. 温度:热、常温、冷等;
如果需要设计一个点餐系统,来生成咖啡订单,如何在系统中将上面说到的拥有4个属性的咖啡生成呢?
第一种方法:
为每种咖啡组合编写不同的类,共有:3*3*3*3=81种类
第二种方法:
针对第一种方法,我们能不能单独定义每种属性,并让每种属性能够复用,然后将他们组合/聚合起来形成一杯咖啡呢?这样就减少每个属性的重复定义了。 例如: 1. 口味:摩卡、拿铁、美式等分别定义一个类,共3个类。 2. 容量:大杯、中杯、小杯等分别定义一个类,共3个类 。3. 添加物:牛奶、糖、蜂蜜等分别定义一个类,共3个类 。4. 温度:热、常温、冷等分别定义一个类,共3个类。所以共有3+3+3+3=12个类,类的数量大减。
桥接模式就是为了实现上面的第二种方法的,先进行抽象,然后通过桥接将属性连接起来。
进一步优化如下图:
咖啡的最重要的属性就是口味(也可以说是本质的属性),其它的属性相对来说不是最重要的,那么我们就让口味直接通过继承的方式实现属性的集成,其它三个属性为了提升替换性/重用性,可以也进行一个抽象类的定义,然后去具体实现。这样设计后,通过组合/聚合实现了咖啡多个属性的集成,减少了类的数量。结构模式图如下:
结合组成角色分析:
抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用,就是上面所说的Coffe抽象类。
修正抽象化(RefinedAbstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义,就是上面的口味实现类。
实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。就是上面的容量、温度、添加物抽象类。
具体实现化(ConcreteImplementor)角色:这个角色给出实现化角色接口的具体实现,就是上面的容量、温度、添加物实现类。
五,代码实现与分析
抽象化(Abstraction)角色:
Coffe抽象类-AbstractCoffe类的定义
public abstract class AbstractCoffe {
// 重点:此处就是连接其它属性的关键,通过成员变量的方式聚合了其它属性
ICapacity capacity;
IAdditives additives;
ITemperature temperature;
// 此处通过有参构造的方式接受客户端想要的咖啡属性
public AbstractCoffe(ICapacity capacity,IAdditives additives,ITemperature temperature){
this.capacity = capacity;
this.additives = additives;
this.temperature = temperature;
}
public abstract void Order(int count);
}
修正抽象化(RefinedAbstraction)角色:
口味实现类-MocaCoffe类定义,只实现了一种类型,就是摩卡,还可以实现其它的口味类型,代码类似,此处就省略了。
public class MocaCoffe extends AbstractCoffe{
public MocaCoffe(ICapacity capacity,IAdditives additives,ITemperature temperature){
super(capacity, additives, temperature);
}
public void Order(int count) {
System.out.println("开始制作摩卡咖啡:");
capacity.SetCupCapacity();
additives.AddAdditives();
temperature.SetTemperature();
System.out.println(count+" 杯Moca Coffe制作完成!");
}
}
实现化(Implementor)角色:
容量、温度、添加物抽象类-ICapacity、ITemperature、IAdditives抽象接口定义
//容量抽象接口ICapacity
public interface ICapacity {
public void SetCupCapacity();
}
//温度抽象接口ITemperature
public interface ITemperature {
public void SetTemperature();
}
//添加物抽象接口IAdditives
public interface IAdditives {
public void AddAdditives();
}
具体实现化(ConcreteImplementor)角色:
容量、温度、添加物实现类-Capacity、Temperature、Additives抽象类定义
(1)Capacity实现类-3种
// 大杯
public class LargeCapacity implements ICapacity{
@Override
public void SetCupCapacity() {
System.out.println("制作杯子尺寸:Large");
}
}
//中杯
public class MiddleCapacity implements ICapacity{
@Override
public void SetCupCapacity() {
System.out.println("制作杯子尺寸:Middle");
}
}
//小杯
public class SmallCapacity implements ICapacity{
@Override
public void SetCupCapacity() {
System.out.println("制作杯子尺寸:Small");
}
}
(2)Temperature实现类-3种
// 热饮
public class HotTemperature implements ITemperature{
@Override
public void SetTemperature() {
System.out.println("加热温度至:Hot");
}
}
// 冷饮
public class NormalTemperature implements ITemperature{
@Override
public void SetTemperature() {
System.out.println("加热温度至:Normal");
}
}
// 常温
public class ColdTemperature implements ITemperature{
@Override
public void SetTemperature() {
System.out.println("加热温度至:Cold");
}
}
(3)Additives实现类-3种
// 加奶
public class MilkAdditives implements IAdditives{
@Override
public void AddAdditives() {
System.out.println("添加 MILK 成功!");
}
}
// 加糖
public class SugarAdditives implements IAdditives{
@Override
public void AddAdditives() {
System.out.println("添加 SUGAR 成功!");
}
}
// 加蜂蜜
public class HoneyAdditives implements IAdditives {
@Override
public void AddAdditives() {
System.out.println("添加 HONEY 成功!");
}
}
客户端测试类定义
public class Main {
public static void main(String[] args) {
// 客户端传入想要的咖啡各个属性的具体对象
AbstractCoffe mocaCoffe = new MocaCoffe(new MiddleCapacity(),new SugarAdditives(),new ColdTemperature());
mocaCoffe.Order(4);
}
}