【设计模式】结构型-桥接模式

news2025/1/12 12:03:12

当抽象与实现,各自独立, 桥接模式,如彩虹桥,连接两岸。

文章目录

  • 一、类爆炸与代码重复
  • 二、桥接模式
  • 三、桥接模式的核心组成
  • 四、运用桥接模式
  • 五、桥接模式的应用场景
  • 六、小结
  • 推荐阅读

一、类爆炸与代码重复

场景假设:假设我们正在设计一个模拟城市交通的系统。在这个系统中,我们有各种类型的桥梁,如悬索桥和拱桥,以及各种类型的车辆,如汽车和自行车。我们希望能够模拟各种车辆在各种桥梁上行驶的情况。

// SuspensionBridgeCar 类代表在悬索桥上驾驶汽车的情况
class SuspensionBridgeCar {
    public void drive() {
        System.out.println("Driving a car on a suspension bridge");
    }
}

// ArchBridgeCar 类代表在拱桥上驾驶汽车的情况
class ArchBridgeCar {
    public void drive() {
        System.out.println("Driving a car on an arch bridge");
    }
}

// SuspensionBridgeBicycle 类代表在悬索桥上骑自行车的情况
class SuspensionBridgeBicycle {
    public void drive() {
        System.out.println("Riding a bicycle on a suspension bridge");
    }
}

// ArchBridgeBicycle 类代表在拱桥上骑自行车的情况
class ArchBridgeBicycle {
    public void drive() {
        System.out.println("Riding a bicycle on an arch bridge");
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建一个 SuspensionBridgeCar 对象来模拟在悬索桥上驾驶汽车的情况
        SuspensionBridgeCar suspensionBridgeCar = new SuspensionBridgeCar();
        suspensionBridgeCar.drive();  // 输出: "Driving a car on a suspension bridge"

        // 创建一个 ArchBridgeBicycle 对象来模拟在拱桥上骑自行车的情况
        ArchBridgeBicycle archBridgeBicycle = new ArchBridgeBicycle();
        archBridgeBicycle.drive();  // 输出: "Riding a bicycle on an arch bridge"

        // 如果我们想要添加新的桥梁类型或车辆类型,我们需要创建更多的类
        // 例如,如果我们想要添加“跳绳桥”和“摩托车”,我们需要创建四个新的类:
        // JumpRopeBridgeCar, JumpRopeBridgeBicycle, SuspensionBridgeMotorcycle, ArchBridgeMotorcycle
    }
}

在这个例子中,我们可以看到以下问题:

  1. 类的数量爆炸:我们需要为每种桥梁和车辆的组合创建一个新的类。这使得代码难以管理和维护。
  2. 代码重复:在每个子类中,我们可能需要重复相同的代码,这违反了 DRY(Don`t Repeat Yourself)原则。

二、桥接模式

桥接模式是一种结构型设计模式,它主要解决的是“将抽象部分与实现部分分离,使它们可以独立地变化”。它通过提供一个桥接结构,把抽象和实现解耦,使得二者可以独立地变化和复用。

在桥接模式中,有两个独立变化的维度:抽象化(Abstraction)和实现化(Implementation)。抽象化是主要的业务逻辑,而实现化是抽象化依赖的底层实现。桥接模式的目标是将这两个维度分离,使它们可以独立地变化和复用,而不是创建一个包含所有可能组合的类。

三、桥接模式的核心组成

桥接模式由以下几个关键角色组成:

  1. 抽象类(Abstraction): 定义了抽象部分的接口,并包含一个指向实现部分对象的引用。抽象类可以包含一些基本操作,而具体的实现则由实现部分提供。
  2. 扩展抽象类(Refined Abstraction): 是对抽象类的扩展,可以添加更多的功能或细化抽象类定义的接口。扩展抽象类通过调用实现部分对象的方法来实现具体的功能。
  3. 实现接口(Implementor): 定义了实现部分的接口,通常包含一组操作方法。实现接口不关心抽象部分的接口,它只负责实现具体的功能。
  4. 具体实现类(Concrete Implementor): 实现了实现接口的具体功能。具体实现类负责实现实现接口定义的操作方法,并与抽象部分的接口进行对应。

在这里插入图片描述

在这个类图中:

  1. Abstraction 是抽象化角色,它定义了基于 Implementor 接口(实现化角色)的高级操作。
  2. RefinedAbstraction 是扩展抽象化角色,它提供了对 Implementor 的具体实现。
  3. Implementor 是实现化角色,它定义了抽象化角色依赖的底层操作。
  4. ConcreteImplementorAConcreteImplementorB 是具体实现化角色,它们实现了 Implementor 接口。

四、运用桥接模式

场景假设:假设我们正在设计一个模拟城市交通的系统。在这个系统中,我们有各种类型的桥梁,如悬索桥和拱桥,以及各种类型的车辆,如汽车和自行车。我们希望能够模拟各种车辆在各种桥梁上行驶的情况。

  1. 创建实现接口: 在桥接模式中,首先我们需要创建一个实现接口,该接口定义了实现部分的操作方法。

    interface Vehicle {
        // 这个接口定义了一些方法,这些方法将在具体的实现类中实现。
        void operate();
    }
    
  2. 创建具体实现类: 接着,我们需要创建具体实现类,实现实现接口中定义的具体功能。

    // `Car`实现了`Vehicle`接口,它提供了`operate`方法的具体实现。
    class Car implements Vehicle {
        public void operate() {
            System.out.println("car");
        }
    }
    
    // `Bicycle`也实现了`Vehicle`接口,它的实现方式与`Car`类似。
    class Bicycle implements Vehicle {
        public void operate() {
            System.out.println("bicycle");
        }
    }
    
  3. 创建抽象类: 接下来,我们创建一个抽象类,该类将持有一个实现接口的引用,并提供一些操作方法,这些方法将委托给实现接口来实现具体的功能。

    abstract class Bridge {
        // 这个类包含一个`Vehicle`类型的成员变量,这个变量是实现部分的接口。
        protected Vehicle vehicle;
    
        // 构造函数接收一个`Vehicle`对象,并将其赋值给成员变量。
        public Bridge(Vehicle vehicle) {
            this.vehicle = vehicle;
        }
    
        // 定义抽象方法`drive`,具体的实现将在子类中完成。
        public abstract void drive();
    }
    
  4. 创建具体实现类: 进一步,我们创建具体实现类,继承自抽象类,并实现抽象类中的抽象方法。

    // `SuspensionBridge`是`Bridge`的子类,它实现了`drive`方法。
    class SuspensionBridge extends Bridge {
        public SuspensionBridge(Vehicle vehicle) {
            super(vehicle);
        }
    
        public void drive() {
            System.out.print("Driving on a suspension bridge in a ");
            vehicle.operate();
        }
    }
    
    // `ArchBridge`也是`Bridge`的子类,它的实现方式与`SuspensionBridge`类似。
    class ArchBridge extends Bridge {
        public ArchBridge(Vehicle vehicle) {
            super(vehicle);
        }
    
        public void drive() {
            System.out.print("Driving on an arch bridge in a ");
            vehicle.operate();
        }
    }
    
  5. 在客户端使用桥接模式: 最后,在客户端代码中使用桥接模式,通过创建具体的对象并调用其方法来操作电视。

    // 在客户端代码中,我们创建了一个`SuspensionBridge`对象和一个`Car`对象,并将它们组合在一起。
    public class Main {
        public static void main(String[] args) {
            Bridge bridge = new SuspensionBridge(new Car());
            bridge.drive();  // Output: "Driving on a suspension bridge in a car"
        }
    }
    

通过上面的桥接模式,通过将抽象(桥梁)和实现(车辆)分离,使它们可以独立地变化。这样,可以更灵活地添加新的桥梁或车辆,而不需要为每种组合创建一个新的类。

五、桥接模式的应用场景

桥接模式主要适用于以下几种场景:

  1. 独立变化的维度:当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时,可以使用桥接模式。
  2. 不希望使用多重继承或因多重继承导致的类爆炸:桥接模式可以替代多重继承方案,它减少了子类的个数。
  3. 接口或抽象类不稳定:如果系统的抽象部分和具体部分需要独立地变化,那么桥接模式可以保证系统的持续运行。
  4. 重用性要求较高:桥接模式中的抽象部分和实现部分都可以独立地扩展,这有助于提高系统的重用性。

以下是一些具体的应用场景:

  1. 跨平台图形和文字处理软件:在这种软件中,形状和颜色、字体和字号等因素可以独立变化,使用桥接模式可以将这些因素的实现从抽象中分离出来,使得它们可以独立地变化。

    // 形状的抽象类
    abstract class Shape {
        protected Color color;
    
        protected Shape(Color color) {
            this.color = color;
        }
    
        abstract void draw();
    }
    
    // 圆形
    class Circle extends Shape {
        protected Circle(Color color) {
            super(color);
        }
    
        void draw() {
            System.out.println("Draw a circle with " + color.getColor());
        }
    }
    
    // 矩形
    class Rectangle extends Shape {
        protected Rectangle(Color color) {
            super(color);
        }
    
        void draw() {
            System.out.println("Draw a rectangle with " + color.getColor());
        }
    }
    
    // 颜色的接口
    interface Color {
        String getColor();
    }
    
    // 红色
    class Red implements Color {
        public String getColor() {
            return "red";
        }
    }
    
    // 蓝色
    class Blue implements Color {
        public String getColor() {
            return "blue";
        }
    }
    
    public static void main(String[] args) {
        Shape redCircle = new Circle(new Red());
        redCircle.draw();
    
        Shape blueRectangle = new Rectangle(new Blue());
        blueRectangle.draw();
    }
    
  2. 驱动程序:驱动程序中的操作系统和硬件设备是两个独立变化的维度,使用桥接模式可以将它们分离,使得操作系统可以在不同的硬件设备上运行,同时硬件设备也可以接入不同的操作系统。

    // 操作系统的抽象类
    abstract class OperatingSystem {
        protected Device device;
    
        protected OperatingSystem(Device device) {
            this.device = device;
        }
    
        abstract void run();
    }
    
    // Windows 操作系统
    class Windows extends OperatingSystem {
        protected Windows(Device device) {
            super(device);
        }
    
        void run() {
            System.out.println("Run Windows on " + device.getDevice());
        }
    }
    
    // Linux 操作系统
    class Linux extends OperatingSystem {
        protected Linux(Device device) {
            super(device);
        }
    
        void run() {
            System.out.println("Run Linux on " + device.getDevice());
        }
    }
    
    // 硬件设备的接口
    interface Device {
        String getDevice();
    }
    
    // Dell 设备
    class Dell implements Device {
        public String getDevice() {
            return "Dell";
        }
    }
    
    // HP 设备
    class HP implements Device {
        public String getDevice() {
            return "HP";
        }
    }
    
    public static void main(String[] args) {
        OperatingSystem windowsOnDell = new Windows(new Dell());
        windowsOnDell.run();
    
        OperatingSystem linuxOnHP = new Linux(new HP());
        linuxOnHP.run();
    }
    
  3. 数据库连接:在数据库连接中,数据库类型(如 MySQL、Oracle)和连接方式(如 ODBC、JDBC)是两个独立变化的维度,使用桥接模式可以将它们分离,使得可以灵活地组合不同的数据库类型和连接方式。

    // 数据库的抽象类
    abstract class Database {
        protected Connection connection;
    
        protected Database(Connection connection) {
            this.connection = connection;
        }
    
        abstract void connect();
    }
    
    // MySQL 数据库
    class MySQL extends Database {
        protected MySQL(Connection connection) {
            super(connection);
        }
    
        void connect() {
            System.out.println("Connect to MySQL with " + connection.getConnection());
        }
    }
    
    // Oracle 数据库
    class Oracle extends Database {
        protected Oracle(Connection connection) {
            super(connection);
        }
    
        void connect() {
            System.out.println("Connect to Oracle with " + connection.getConnection());
        }
    }
    
    // 连接方式的接口
    interface Connection {
        String getConnection();
    }
    
    // ODBC 连接
    class ODBC implements Connection {
        public String getConnection() {
            return "ODBC";
        }
    }
    
    // JDBC 连接
    class JDBC implements Connection {
        public String getConnection() {
            return "JDBC";
        }
    }
    
    public static void main(String[] args) {
        Database mySqlWithODBC = new MySQL(new ODBC());
        mySqlWithODBC.connect();
    
        Database oracleWithJDBC = new Oracle(new JDBC());
        oracleWithJDBC.connect();
    }
    

六、小结

桥接模式是一种强大的设计模式,它能够有效地解耦抽象和实现,使系统更加灵活和可扩展。通过将抽象部分和实现部分分离,桥接模式使得我们可以轻松地扩展和变化系统的功能,而不会影响原有的代码结构。在实际应用中,我们可以根据具体的需求来选择是否使用桥接模式,以达到更好的设计和开发效果。

推荐阅读

  1. Spring 三级缓存
  2. 深入了解 MyBatis 插件:定制化你的持久层框架
  3. Zookeeper 注册中心:单机部署
  4. 【JavaScript】探索 JavaScript 中的解构赋值
  5. 深入理解 JavaScript 中的 Promise、async 和 await

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1811115.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++第二十六弹---stack和queue的基本操作详解与模拟实现

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】 目录 1. stack的介绍和使用 1.1 stack的介绍 ​1.2 stack的使用 1.3 stack 模拟实现 2. queue的介绍和使用 2.1 queue的介绍 2.2 queue的使用 2…

5.31.15 使用图像到图像转换和 YOLO 技术对先前的乳房 X 光检查结果中的异常进行早期检测和分类

在本研究中,我们研究了基于 You-Only-Look-Once (YOLO) 架构的端到端融合模型的有效性,该模型可同时检测和分类数字乳房 X 光检查中的可疑乳腺病变。包括四类病例:肿块、钙化、结构扭曲和正常,这些病例来自包含 413 个病例的私人数…

一次曝 9 个大模型,「字节 AI」这一年都在做什么?

字节跳动的大模型家族,会长出下一个抖音吗? 整个 2023 年,字节并没有对外官宣其内部自研的大模型。外界一度认为,大模型这一技术变革,字节入场晚了。梁汝波在去年底的年会上也提到了这一点,他表示「字节对…

【全开源】露营地管理系统小程序源码(ThinkPHP+FastAdmin+UniApp)

专为露营业务设计开发小程序应用。平台拥有多角色管理,同时具有营位预定、门票购买等功能模块。 🔥露营地管理系统小程序:轻松掌控你的露营帝国🏕️ 📌一、引言:露营地管理的新时代 随着露营文化的兴起&a…

❤vue2项目webpack打包的优化策略

❤ vue2项目webpack打包的优化策略 (优化前) 现在我们的打包时间为: >打包体积大小为: 1、去除开发环境和生产环境提示以及日志 开发环境和生产环境的打印处理 生产环境去除console.log打印的两种方式 通过环境变量控制co…

知识图谱的应用---社交网络

文章目录 社交网络典型应用 社交网络 社交网络已成为发展最快的互联网应用,社交网络用户不仅仅是信息的接受者,也成为了信息的制造、加工和传播者,通过关注、被关注的方式形成了一张张庞杂繁复的用户关系网。随着社交网络中用户及信息急速增长…

数新网络签单国泰君安:利用数据服务平台提升金融业务用数能力

近日,数新网络与国泰君安证券股份有限公司(以下简称“国泰君安”)达成了数据服务平台升级项目的签约。这一项目的推进将更好地服务于国泰君安内部业务部门的数据需求,帮助数据平台更加有效地实现提升业务响应效率的目标&#xff0…

【Linux文件篇】系统文件、文件描述符与重定向的实用指南

W...Y的主页 😊 代码仓库分享💕 前言:相信大家对文件都不会太陌生、也不会太熟悉。在没有学习Linux操作系统时,我们在学习C或C时都学过如何去创建、打开、读写等待文件的操作,知道一些语言级别的一些接口与函数。但…

怎样把便签里的内容移到桌面?桌面便签软件使用方法

每次打开电脑,我总是被满屏的文件和图标弄得眼花缭乱。那些记录在各式各样便签里的重要事项,经常被埋没在这信息的海洋中,找起来真是头疼。想必很多人都有过这样的困扰:如何在繁杂的桌面环境中,一眼就看到自己需要提醒…

问题:以下被纳入代理资产风险分类管理的业务包括() #媒体#知识分享

问题:以下被纳入代理资产风险分类管理的业务包括() A.非标准化理财投资业务 B.特定债权投资业务 C.委托债权代理业务 D.非标准化代理销售业务 参考答案如图所示

HTML静态网页成品作业(HTML+CSS)—— 兰蔻化妆品网页(1个页面)

🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有1个页面。 二、作品演示 三、代…

NAT

文章目录 1.NAT是什么2.NAT功能3.NAT优缺点4.NAT作用工作原理5.NAT 静态 动态5.1静态静态配置1.全局模式下设置静态NAT2.接口上设置静态NAT 5.2动态动态配置测试 6.PAT多路复用 PAT NAPT Easyip NAT server6.1PAT端口多路复用PAT作用 1.NAPT配置测试 2.EasyIp配置测试 3.NAT se…

Fegin如何传参form-data文件

Form-data传输file参数,这个大家都比较清楚,那么针对于Fegin参数file参数该如何操作呢!下面截图来找到对应的参数关系。 一、之前我们在postMan中是这种传参的,那么如果使用Feigin来传输文件File 二、在Fegin中传form-data参数&a…

Qt系统相关

本文目录 1.Qt事件事件的处理标签事件鼠标事件滚轮事件按键事件定时器事件窗口事件事件派发器 2.Qt文件操作QFile的基本使用 3.Qt多线程使用线程线程锁connect的第五个参数 条件变量和信号量 4.Qt网络编程UDP SocketTCP SocketQTcpServerQTcpSocket HTTP的编写 5.QT多媒体播放音…

【区块链】深入解析Proof of Work (PoW): 区块链技术的核心驱动力

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 深入解析 Proof of Work (PoW): 区块链技术的核心驱动力引言一、PoW基本概念1.1…

UNetMultiLane 多车道线、车道线类型识别

基于UNet 分割模型增加了检测头来识别车道线的类型(单实线、双黄线等10种),同时可以识别出"所在车道"和"车道线类型"。 训练代码【训练练手代码】 1 数据说明 基于开源数据集 VIL100。其中数据标注了所在的六个车道的车…

大福利!微信付费进群源码

微信付费进群源码 前言效果图搭建教程源码领取下期更新预报 前言 1、修复SQL表 2、修复支付文件 3、修复支付图标不显示 4、修复定位、分销逻辑、抽成逻辑 5、新增支持源支付、易支付的支付接口 6、修复官方微信、支付宝支付接口文件 本来早就可以完工的,电脑…

苹果WWDC 2024速览

引言 2024年苹果全球开发者大会(WWDC)在充满科技感的苹果园区拉开帷幕,本次大会发布了众多令人振奋的软硬件更新,包括Vision OS 2、iOS 18、watchOS 11和macOS Sequoia的重大创新。本文将详细解读这些更新,为您展示它…

来自中国信通院的认可!上海斯歌受邀加入“EP-Link 智能流程推进计划”

5月30日,由中国信息通信研究院主办的“EP-Link 智能流程推进计划”周年产业研讨会在北京隆重召开。会上,在众多领袖专家、行业翘楚的见证下,上海斯歌被中国信息通信研究院授予“EP-Link 智能流程推进计划”成员单位证书,正式加入该…

Vxe UI vxe-modal 实现窗口的最大化与最小化,实现弹出多窗口

Vxe UI vue vxe-modal 实现窗口的最大化与最小化,实现弹出多窗口 通过js方式调用 js方式脱离模板,每次创建是多个实例。 mask:关闭遮罩层,如果不关闭则会显示遮罩层,就不能实现同时操作多窗口 lockView:…