是设计模式,我们有救了!!!(六、桥接模式)

桥接模式--解耦抽象与实现的设计艺术

其核心思想是将抽象部分与实现部分分离 ,使它们可以独立变化而不互相影响。这种模式通过组合关系替代继承关系 ,有效解决了多维度变化导致的类爆炸问题,提高了系统的灵活性和可扩展性。

让我们来举一个做咖啡为基础的场景说明一些问题: 假设我们的咖啡只有两个维度: 制作咖啡本身的流程makeCoffee,和添加一些不属于咖啡本身的东西(比如、加糖,加奶、加柠檬之类的)。那么现在我们的抽象就是这样的:

csharp 复制代码
public abstract class BaseCoffee {
    public abstract String add();
    public abstract void makeCoffee();
}

至于具体的实现,我们可以放在子类当中去做: 因此我们可能会想去制作加糖的美式咖啡

scala 复制代码
public class AmericanCoffeeSugar extends BaseCoffee{
    @Override
    public String add() {
        return "加糖";
    }

    @Override
    public void makeCoffee() {
        System.out.println("美式咖啡"+add());
    }
}

也可能是加奶的意式咖啡

scala 复制代码
public class ItalianCoffeeMilk extends BaseCoffee {
    @Override
    public String add() {
        return "加奶";
    }

    @Override
    public void makeCoffee() {
        System.out.println("意式咖啡" + add());
    }
}

当然,我们现在不考虑好不好喝的问题,为了尽可能的满足客户端的需要,我们必须要提供每种制作工艺(makeCoffee)和额外添加(add)的组合。 现在再回过头来看问题:

  • 抽象部分与实现部分分离?

  • 当然没有分离,我们的耦合度其实很高。比如如果我想做一个不加糖的美式咖啡,必须要重写一个子类。

  • 类爆炸?

  • 没错,我们做到了!实际子类的数量就可以达到N(咖啡品种)xM(额外添加物品种)的数量级。

来看桥接模式是怎么做的:

csharp 复制代码
public abstract class BaseCoffee{
    //关键步骤,将会引起某一维度变化的属性抽象为接口,子类中在引入抽象的具体实现
    protected CoffeeAdditive additive;

    public BaseCoffee(CoffeeAdditive additive){
        this.additive = additive;
    }
    public abstract void makeCoffee();
}

将add这一抽象方法,放在一个接口里,让实现了该接口的类实现该方法。

csharp 复制代码
public interface CoffeeAdditive {
    public String add();
}

具体的添加实现类有:

typescript 复制代码
public class Lemon implements CoffeeAdditive{
    @Override
    public String add() {
        return "加柠檬";
    }
}
typescript 复制代码
public class Milk implements CoffeeAdditive{
    @Override
    public String add() {
        return "加奶";
    }
}
typescript 复制代码
public class Sugar implements CoffeeAdditive{
    @Override
    public String add() {
        return "加糖";
    }
}

那么现在来看,在M维度上,我们只增加了M个实现类对吧。 再来看另一个维度,原来的子类被我们改成如下:

scala 复制代码
public class AmericanCoffee extends BaseCoffee{
    public AmericanCoffee(CoffeeAdditive additive) {
        super(additive);
    }

    @Override
    public void makeCoffee() {
        System.out.println("美式咖啡" + this.additive.add());
    }
}

这时候的子类只需要实现makeCoffee这一方法就好,因为原来的add方法已经被CoffeeAdditive实现类,只需要无脑调用即可。如此,在N维度上我们也只增加了N个类。最终的实现类和子类只会有N+M个。 当在客户端调用时:

java 复制代码
public class Client {
    public static void main(String[] args) {
        AmericanCoffee americanCoffee = new AmericanCoffee(new Milk());
        americanCoffee.makeCoffee();

        Cappuccino cappuccino = new Cappuccino(new Sugar());
        cappuccino.makeCoffee();

    }
}
相关推荐
鬼火儿4 小时前
SpringBoot】Spring Boot 项目的打包配置
java·后端
cr7xin4 小时前
缓存三大问题及解决方案
redis·后端·缓存
间彧5 小时前
Kubernetes的Pod与Docker Compose中的服务在概念上有何异同?
后端
间彧5 小时前
从开发到生产,如何将Docker Compose项目平滑迁移到Kubernetes?
后端
间彧5 小时前
如何结合CI/CD流水线自动选择正确的Docker Compose配置?
后端
间彧5 小时前
在多环境(开发、测试、生产)下,如何管理不同的Docker Compose配置?
后端
间彧5 小时前
如何为Docker Compose中的服务配置健康检查,确保服务真正可用?
后端
间彧5 小时前
Docker Compose和Kubernetes在编排服务时有哪些核心区别?
后端
间彧5 小时前
如何在实际项目中集成Arthas Tunnel Server实现Kubernetes集群的远程诊断?
后端
brzhang6 小时前
读懂 MiniMax Agent 的设计逻辑,然后我复刻了一个MiniMax Agent
前端·后端·架构