设计模式之桥接模式

一、介绍

桥接模式,是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立地变化。桥接模式通过组合的方式建立两个类之间的联系,而不是继承

二、角色

Abstraction(抽象类):定义抽象类的接口,维护实现类对象的引用

RefinedAbstraction(扩充抽象类):扩充抽象类,改变和修正父类对抽象的定义

Implementor(实现类接口):定义实现类的接口

ConcreteImplementor(具体实现类):实现实现类接口,定义具体的实现

三、案例

定义实现化角色的接口

复制代码
public interface Color {
    void applyColor();
}

**定义具体实现化角色:**给出实现化(Implementor)角色接口的具体实现

java 复制代码
public class Red implements Color{
    @Override
    public void applyColor() {
        System.out.println("Applying red color");

    }
}
java 复制代码
public class Blue implements Color{
    @Override
    public void applyColor() {
        System.out.println("Applying blue color");
    }
}

定义抽象化(Abstraction)角色:里面包含了对实现化角色的接口的引用

java 复制代码
public abstract class Shape {
    protected Color color;
    public Shape(Color color) {
        this.color = color;
    }
    public abstract void applyColor();
}

定义扩展抽象化(Refined Abstraction)角色:是抽象化(Abstraction)角色的子类,实现父类中的业务方法,并通过组合关系调用实现化(Implementor)角色中的业务方法

java 复制代码
public class Circle extends Shape {

    public Circle(Color color) {
        super(color);
    }

    @Override
    public void applyColor() {
        System.out.print("Circle applying color: ");
        color.applyColor();
    }
}
java 复制代码
public class Square extends Shape{

    public Square(Color color) {
        super(color);
    }
    @Override
    public void applyColor() {
        System.out.print("Square applying color: ");
        color.applyColor();

    }
}

测试

四、慢动作演示桥接

我们假设一部手机有三个重要部件:电池(Battery)摄像头(Camera)屏幕(Screen)。当我们拍摄一张高清照片时,需要充足的电量、高像素的摄像头、高分辨率的屏幕

于是我们可以通过下面的代码完成拍照动作:

  • 电池Battery
java 复制代码
public class Battery {
    public Battery() {
        System.out.println("充足电量的电池");
    }
    
    public void electric() {
        System.out.println("电池供电...");
    }
}
  • 摄像头Camera
java 复制代码
public class Camera {
    public Camera() {
        System.out.println("高清像素的摄像头");
    }
    
    public void catchImg() {
        System.out.println("摄像头捕获图像...");
    }
}
  • 屏幕Screen
java 复制代码
public class Screen {
    public Screen() {
        System.out.println("高分辨率的屏幕");
    }
    
    public void show() {
        System.out.println("屏幕显示照片...");
    }
}
  • 手机Phone
java 复制代码
public class Phone {
    private Battery battery;
    private Camera camera;
    private Screen screen;

    public Phone(Battery battery, Camera camera, Screen screen) {
        this.battery = battery;
        this.camera = camera;
        this.screen = screen;
    }

    public void takePic() {
        System.out.println("手机拍照开始...");
        // 电池供电
        battery.electric();
        // 摄像头捕获图像
        camera.catchImg();
        // 屏幕显示照片
        screen.show();
    }
}

测试

从该案例中可以看出,电池、摄像头、屏幕这三个组件是相互独立的,各自干各自的活,通过手机将他们连接起来就可以进行拍照,这时手机就表现为桥梁的角色。通过桥梁,三个组件相互独立

1. 组件抽象化

在实际现实中,无论是电池、摄像头、还是屏幕,他们都有各自的品牌厂商,因此我们需要将他们抽象化。如电池有南孚和山羊;摄像头有索尼和徕卡;屏幕有三星和京东方

所有我们需要做出修改:新建电池、摄像头、屏幕的抽象类;再分别按照品牌厂商对这些抽象类进行实现。

电池抽象类Battery ,及其实现类:南孚电池(NanFu)山羊电池(Sheep)

java 复制代码
public interface IBattery {
    void electric();
}

public class NanFu implements IBattery{

    public NanFu() {
        System.out.println("南孚电池实例化");
    }
    @Override
    public void electric() {
        System.out.println("南孚电池正在供电...");

    }
}

public class Sheep implements IBattery{
    public Sheep() {
        System.out.println("山羊电池实例化");
    }
    @Override
    public void electric() {
        System.out.println("山羊电池正在供电...");

    }
}

摄像头抽象类Camera ,及其实现类:徕卡摄像头(Laika)索尼摄像头(Sony)

java 复制代码
public interface ICamera {
    void catchImg();
}

public class Laika implements ICamera{
    public Laika() {
        System.out.println("徕卡摄像头实例化");
    }

    @Override
    public void catchImg() {
        System.out.println("徕卡摄像头捕获图像...");
    }
}

public class Sony implements ICamera {
        public Sony() {
            System.out.println("索尼摄像头实例化");
        }

        @Override
        public void catchImg() {
            System.out.println("索尼摄像头捕获图像...");
        }
}

屏幕抽象类Screen ,及其实现类:京东方显示屏(JingDongFang)三星显示屏(SanXing)

java 复制代码
public interface IScreen {
    void show();
}

public class JingDongFang implements IScreen {
    public JingDongFang() {
        System.out.println("京东方显示屏实例化");
    }

    @Override
    public void show() {
        System.out.println("京东方显示屏显示照片...");
    }
}

public class SanXing implements IScreen {
    public SanXing() {
        System.out.println("三星显示屏实例化");
    }

    @Override
    public void show() {
        System.out.println("三星显示屏显示照片...");
    }
}

这样一来,手机的构造方法的参数就由原来的具体实现类变成了抽象类。

java 复制代码
  public Phone(IBattery battery, ICamera camera, IScreen screen) {
        this.battery = battery;
        this.camera = camera;
        this.screen = screen;
    }

2. 桥梁抽象化

其实不仅电池、摄像头、屏幕有自己的品牌厂商,手机也不例外,如华为、oppo、vivo等,因此我们也需要将手机这个桥梁的角色抽象化。但是如果我们将该桥梁设计成一个接口,由不同的手机品牌实现该接口,那么就可能会导致不同的实现类具有不同参数的构造方法,如此一来,所有品牌手机的功能虽然受到约束(实现类手机接口),但是他们的组成结构却千差万别。如下所示

java 复制代码
public interface IMyPhone{
    /**
     * 拍照
     */
    void takePic();
    /**
     * 通话
     */
    void call();

    /**
     * 微信聊天
     */
    void wechat();
}

public class Vivo implements IMyPhone{
    private ComponentC componentC;
    private ComponentD componentD;
    public Vivo(ComponentC componentC,ComponentD componentD){
        this.componentC = componentC;
        this.componentD = componentD;
    }
    @Override
    public void takePic() {
        System.out.println("Vivo takePic");
    }

    @Override
    public void call() {
        System.out.println("Vivo call");
    }

    @Override
    public void wechat() {
        System.out.println("Vivo wechat");
    }
}



public class Oppo implements IMyPhone{
    private ComponentA componentA;
    private ComponentB componentB;
    public Oppo(ComponentA componentA,ComponentB componentB){
        this.componentA = componentA;
        this.componentB = componentB;
    }

    @Override
    public void takePic() {
        System.out.println("Oppo takePic");
    }

    @Override
    public void call() {
        System.out.println("Oppo call");
    }

    @Override
    public void wechat() {
        System.out.println("Oppo wechat");
    }
}

从上面的代码来看,oppo和vivo虽然实现了手机(IMyPhone)定义的所有功能,但是却乱七八糟的,oppo手机内部组件是ComponentA和ComponentB,vivo手机内部组件却是ComponentC和ComponentD。这样的话手机行业岂不乱套了。

所以我们对桥梁的抽象化不应采用接口,而是抽象类。

使用抽象类有一个好处是,可以使所有子类拥有相同的内部属性,而且对所有子类的构造方法也做出了约束。

如下所示,我们将手机抽象化一个手机接口(Phone)来定义各个功能,再通过一个抽象子类(AbstractPhone)实现手机接口定义的功能,并规范构造方法,由华为(HuaWei)、**小米(XiaoMi)**两个品牌继承该抽象子类

java 复制代码
public interface IMyPhone {
    /**
     * 拍照
     */
    void takePic();
}


public abstract  class AbstractPhone implements IMyPhone {
    private IBattery battery;
    private ICamera camera;
    private IScreen screen;

    public AbstractPhone(IBattery battery, ICamera camera, IScreen screen) {
        this.battery = battery;
        this.camera = camera;
        this.screen = screen;
    }
    @Override
    public void takePic() {
        System.out.println("手机拍照开始...");
        // 电池供电
        battery.electric();
        // 摄像头捕获图像
        camera.catchImg();
        // 屏幕显示照片
        screen.show();
    }
}

public class XiaoMi extends AbstractPhone {
    public XiaoMi(IBattery battery, ICamera camera, IScreen screen) {
        super(battery, camera, screen);
        System.out.println("小米手机");
    }
}

public class HuaWei extends AbstractPhone {
    public HuaWei(IBattery battery, ICamera camera, IScreen screen) {
        super(battery, camera, screen);
        System.out.println("华为手机");
    }
}

通过接口(定义功能)抽象子类(桥梁)、**实现类(实现功能)**的方式,就是桥接设计模式的实现。

测试

五、适用场景

  • 图形绘制:形状和绘制API的分离
  • 消息发送:消息类型和发送方式的分离
  • 数据库访问:数据访问对象和数据库连接的分离
  • 文件处理:文件类型和存储方式的分离
  • 多平台支持:业务逻辑和平台实现的分离

当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时

当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时

当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时

六、与适配器模式的区别

桥接模式是设计时模式,适配器模式是运行时模式,桥接模式是抽象和实现的分离,适配器模式是接口的转换 ,桥接模式在系统设计时使用,适配器模式在系统集成时使用

七、与适配器模式的区别

桥接模式是结构分离,装饰器模式是功能增强,桥接模式是组合关系,装饰器模式是包装关系

桥接模式支持独立变化,装饰器模式支持功能叠加

八、总结

桥接模式是一种重要的结构型设计模式,它通过将抽象部分与实现部分分离,实现了它们之间的解耦,并支持独立的变化。在实际开发中,桥接模式特别适用于有多个变化维度、需要支持多平台、或者需要解耦抽象和实现的场景。通过合理使用桥接模式,可以大大提高系统的灵活性和可维护性。

相关推荐
model200519 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉19 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国20 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_9418824820 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈20 小时前
两天开发完成智能体平台
java·spring·go
alonewolf_9920 小时前
Spring MVC重点功能底层源码深度解析
java·spring·mvc
沛沛老爹20 小时前
Java泛型擦除:原理、实践与应对策略
java·开发语言·人工智能·企业开发·发展趋势·技术原理
专注_每天进步一点点20 小时前
【java开发】写接口文档的札记
java·开发语言
代码方舟20 小时前
Java企业级实战:对接天远名下车辆数量查询API构建自动化风控中台
java·大数据·开发语言·自动化