【浅谈设计模式】(9):桥接模式--由“手抓饼案例”再次入门

1,074 阅读7分钟

前言

本周的学习计划包括这篇设计模式了。离上次更文也隔了半个多月了,发现设计模式的学习之路本身是一件挺枯燥的事情,但是如果能用一种有趣的方式将出来,我觉得是很厉害的,因此,我在学习的同时也希望能够以更通俗的语言来讲解这些东西。

今天要学的讲的内容是结构型模式的第四种----桥接模式。

一、桥接模式入门

1.1 概述

桥接模式的问题常常用来解决多个维度的问题。比如这张经典的图,河一边是电脑、电视、收音机等设备,而河对岸是各种遥控器,这其实对应两个维度,通过一架高桥完成连接通信。而所谓的“桥”的联系是提取出来的接口的联系,在维度一中调用维度二的接口,然后把接口传入维度一的构造方法中。

桥接设计模式

下面我们继续以浅谈装饰者模式中的手抓饼案例为例,来开始桥接模式的讲解。

假设卖手抓饼的大娘 目前的业务有山东杂粮煎饼、原味手抓饼。现在为了扩大销量,采用了 线下店铺和淘宝电商的多种渠道方式,这就是包括售卖产品和售卖渠道的两种维度。

image-20210717145048709

但是这种定义明显有着一个缺点,就是每增加一种售卖产品,可能相应的就多了好多种售卖渠道的产品,同样的每多一种售卖渠道,就多好多种售卖产品的渠道。无论增加哪一维度,都需要创建更多的类,因此,在一个多种可能会变化的维度的系统中,用继承会造成类爆炸,不灵活,每次在一个维度上新增一个具体实现,都需要增加多个子类,此时就可以考虑桥接模式

桥接模式(Bridge patten),是结构型设计模式的一种,它可以将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构,从而可以在开发时分别使用。

引用百度百科定义:

将抽象部分与它的实现部分分离,使它们都可以独立的变化。

百度百科的定义相对难懂,我们只需要记住桥接模式的特点将抽象和实现分离,在抽象层建立依赖,从而两个维度上的实现类可以进行各自的变化而不会相互影响,具有非常好的扩展性。

1.2 桥接模式结构

桥接模式包含以下角色:

  • 抽象化角色:定义抽象类,并包含一个对实现化对象的引用。
  • 扩展抽象化角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
  • 实现化角色:定义实现化角色的接口,供扩展抽象化角色调用
  • 具体实现化角色:给出实现化角色接口的具体实现。

二、案例讲解

下面,我们开始对前面将的案例进行 demo 还原。

image-20210717162807253

实现化角色:

/**
 * 售卖方式
 * @Author xiaolei
 * @Date 2021/7/17 16:02
 **/
public interface SaleModel {
    void sale(String product);
}

线下店铺售卖 --- 具体实现化角色:

public class OfflineSafe implements SaleModel {
    public void sale(String product) {
        System.out.println("线下店铺售卖:"+product);
    }
}

线上淘宝售卖 --- 具体实现化角色

public class TaoBaoSafe implements SaleModel {
    public void sale(String product) {
        System.out.println("淘宝电商售卖:"+product);
    }
}

产品类:

/**
 * 售卖产品
 **/
public abstract class Product {
    protected SaleModel saleModel;
    public Product(SaleModel saleModel){
        this.saleModel=saleModel;
    }
    public abstract void make(String name);
}
​

手抓饼 -- (抽象化角色子类)

public class HandPancke extends Product {
​
    public HandPancke(SaleModel saleModel) {
        super(saleModel);
    }
​
    public void make(String name) {
        saleModel.sale(name);
    }
}

山东杂粮煎饼类 --(抽象化角色子类)

public class ShandongPancake extends Product {
    public ShandongPancake(SaleModel saleModel) {
        super(saleModel);
    }
​
    public void make(String name) {
        saleModel.sale(name);
    }
}

输出结果:

image-20210717163043470

三、 总结

3.1 优缺点

3.1.1 优点
  • 抽象和实现分离:这是桥接模式的主要特点,也是避免使用继承的主要原因。使用桥接模式,解耦了抽象和实现,使得两者的变化不会对另一方产生影响,使得系统扩展性大大增强。
  • 优秀的扩展能力:桥接模式的出现是为了解决多个独立变化的维度的耦合,其高层模块聚合关系已确定,因此,无论是抽象变化 还是实现 变化,只要对其进行扩展即可,高层代码无序更改,严格遵守了依赖倒置原则。
  • 实现细节对客户透明:由于桥接模式在高层模块中通过聚合关系构建了稳定的架构(封装)。因此,客户只需与高层模块交互,对抽象和实现的细节完全不需关注。
3.1.2 缺点
  • 桥接模式 由于聚合关联关系建立在抽象层,要求开发者对抽象层进行设计与编程,增加系统的理解和设计难度。

3.2 使用场景

桥接模式的一个常用使用场景就是为了替换 继承,继承本身具备强侵入性(父类代码侵入子类),造成子类臃肿,因此,优先使用组合/聚合的方式。

桥接模式的特点是将抽象与实现分离,因此它适合

  • 一个类存在两个或多个独立变化的维度,而且这两个维度都需要扩展
  • 不希望或不适用继承的场景

3.3 模式对比

  • 桥接模式和抽象工厂模式区别:

这个维度的概念,我们在抽象工厂中也提到过,这两者都与多个维度相关。但是抽象工厂模式更关注的是对象的创建,是创建型模式,而桥接模式则是更关注的是对象创建之后的动作或功能,所以区别是在这块。

  • 桥接模式和装饰者模式区别:

在画uml 的时候,发现这两者十分的相似,它们都能够避免类爆炸,把继承变组合,降低了耦合。但是装饰者模式它是封闭的类,需要用同一个接口装饰,接口在父类中定义,而桥接模式不用使用同一个接口。

3.4 小结😄

桥接模式通常会于开发前期进行设计,使你能够将程序的各个部分独立开来以便开发。它的特点将抽象和实现分离,在抽象层建立依赖,从而两个维度上的实现类可以进行各自的变化而不会相互影响,具有非常好的扩展性。

设计模式本身在应用中是有一定难度的,需要一定的业务经验积累,如果哪一天你在哪个底层源码中突然领略到哪个你看过的模式,就值了,如果哪一天,你在面对业务捉急的时候,突然把脑门一拍,哎,要不试试装饰者模式,那你可能就顿悟了,希望那一天离你更近一点。我是潇雷,如果你觉得本文对你有帮助或启发,帮忙点个赞,这将是我创作的最好动力!

四、浅谈设计模式系列👏👏👏