【设计模式】桥接模式在开发中的应用

news2024/11/25 14:23:07

1. 概述

桥接模式是一个非常简单的设计模式,可能大家在开发的过程中已经使用到了这种模式而不自知。总的来说,桥接模式最大的作用就是解耦,所谓的解耦,就是通过转换代码的设计,减少类与类,模块与模块之间的依赖紧密程度。

2.桥接模式

2.1.两种定义

桥接模式的主流定义有两种,第一种是GoF的定义:

将抽象和实现解耦,使得两者可以独立地变化。

通过这句话,我们能够得到的信息是需要降低抽象实现和依赖紧密程度,以达到两者之间可以独立扩展,互不影响的效果。

在大多数情况下,抽象一般指的是接口和抽象类,实现就是实现类。在桥接模式中的抽象和实现,无所谓接口、抽象类还是实现类的差异。桥接模式抽象更多的是提供一定的约束,比如一个固定的执行流程,在这个流程中会定义出一些可以自由替换的口子,而实现就是去适配这些口子,让一个固定的执行流程可以得到不同的执行结果。在这个定义下,桥接模式中的抽闲实现,可能各自都是一套类库,或者是一个独立的模块。

简单的理解,就是抽象会定义要做什么,实现是定义怎么去做,也就理解为插口与插件的关系。
比如:操作系统文件系统的关系、JDBC中连接与数据库驱动之间的关系、Dubbo协议服务提供/调用者的封装之间的关系,都可以看做是这种抽象与实现分离的桥接关系。

除了上述的框架或开源代码之外,我们在实际的开发过程中也经常会有类似的需求。
比如:系统需要接入支付功能的时候,会先定义一套支付流程,在这个流程的节点中会调用不同的三方支付渠道,微信、支付宝等,这里的支付流程就是抽象,支付渠道就是实现。
再比如:需要实现一个消息发送平台,消息发送的流程就是抽象,不同的消息发送渠道(短信、邮件、推送、站内信等)就是实现,更进一步在短信发送中,短信发送的通用流程就是抽象,调用不同的短信发送渠道商就是实现。


第二种定义方式更为简单使用更加广泛:

一个类存在多个独立变化的维度,通过组合的方式让多个维度可以独立进行扩展。

为什么说这种方式更加广泛呢?
思考一下就会发现,在第一种定义中抽象和实现完全可以理解为两个不同的维度,这两个维度都是可以独立变化的,也就是说,第二种定义包含了第一种定义,并在这个基础上扩展了,即使不满足抽象与实现的关系,只要有多个不同的维护可以独立变化,并且通过组合/聚合的方式实现不同维度独立扩招,就可以认为是桥接模式。

举个例子:
还是上面说的消息发送的需求,在短信发送中,常规的短信在服务商那里有两种类型:通知类、营销类
对于营销类型的短信,需要在短信的正文末尾拼接上回T退订回TD退订或者类似的文本,而通知类型的是不需要的,这时候就可以将短信类型作为一个维度,短信渠道作为另一个维度,将两个维度通过组合的方式连接起来,就形成了一个简单的桥接模式实现。
在这个例子中,并没严格的抽象与实现的关系。

2.2.通用类图/通用代码

根据上面的描述,不同维度之间通过组合/聚合的方式进行连接,可以得到如下的类图:
在这里插入图片描述
通用代码实现:

  • 维度B:
    public interface DimensionB {
        void operation();
    }
    
    public class DimensionBImpl implements DimensionB {
        @Override
        public void operation() {
            System.out.println("维度B的实现");
        }
    }
    
  • 维度A:
    public abstract class DimensionA {
    
        private DimensionB dimensionB;
    
        public DimensionA(DimensionB dimensionB) {
            this.dimensionB = dimensionB;
        }
    
        public void operation() {
            dimensionB.operation();
        }
    
    }
    
    public class DimensionAImpl extends DimensionA {
    
        public DimensionAImpl(DimensionB dimensionB) {
            super(dimensionB);
        }
    }
    

2.3.在业务开发中的应用

参照通用的代码和类图,可以在实际的开发中使用桥接模式,以上面讲的不同短信类型为例,简单的实现一下短信发送的业务。

  • 定义发送渠道的维度:
    public interface SmsChannel {
        void send(String message, String phone);
    }
    
    public class AliSmsChannel implements SmsChannel {
       @Override
       public void send(String message, String phone) {
           System.out.println("使用阿里云短信通道发送消息:" + message + ",给:" + phone);
       }
    }
    
  • 定义短信类型维度:
    public abstract class SmsType {
    
        private SmsChannel smsChannel;
    
        public SmsType(SmsChannel smsChannel) {
            this.smsChannel = smsChannel;
        }
    
        public void send(String message, String phone) {
            smsChannel.send(message, phone);
        }
    }
    
    public class NotificationSmsType extends SmsType {
        public NotificationSmsType(SmsChannel smsChannel) {
            super(smsChannel);
        }
    }
    
    public class MarketingSmsType extends SmsType {
    
        public MarketingSmsType(SmsChannel smsChannel) {
            super(smsChannel);
        }
    
        @Override
        public void send(String message, String phone) {
            message = message + " 回T退订";
            super.send(message, phone);
        }
    }
    
  • 测试:
    public class SmsTest {
    
        public static void main(String[] args) {
            SmsType notificationSmsType = new NotificationSmsType(new AliSmsChannel());
            notificationSmsType.send("测试通知类型短信", "18512345678");
    
            System.out.println("=====================================");
    
            SmsType marketingSmsType = new MarketingSmsType(new AliSmsChannel());
            marketingSmsType.send("测试营销类型短信", "18512345678");
        }
    }
    

执行测试的结果如下:

使用阿里云短信通道发送消息:测试通知类型短信,给:18512345678
=====================================
使用阿里云短信通道发送消息:测试营销类型短信 回T退订,给:18512345678


此时要拓展一个腾讯云的发送渠道,只需要创建一个新的SmsChannle,在SmsType的维度上是不用做修改的,主打的就是不同维度独立拓展。

public class TencentSmsChannel implements SmsChannel {
    @Override
    public void send(String message, String phone) {
        System.out.println("使用腾讯云短信通道发送消息:" + message + ",给:" + phone);
    }
}

在做一次测试,对比一下两种渠道:

public class SmsTest {

    public static void main(String[] args) {
        SmsType notificationSmsType = new NotificationSmsType(new AliSmsChannel());
        notificationSmsType.send("测试通知类型短信", "18512345678");

        System.out.println("=====================================");

        SmsType marketingSmsType = new MarketingSmsType(new AliSmsChannel());
        marketingSmsType.send("测试营销类型短信", "18512345678");

        System.out.println("=====================================");

        MarketingSmsType tencentMarketingSmsType = new MarketingSmsType(new TencentSmsChannel());
        tencentMarketingSmsType.send("测试营销类型短信","18512345678");
    }

}

使用阿里云短信通道发送消息:测试通知类型短信,给:18512345678
=====================================
使用阿里云短信通道发送消息:测试营销类型短信 回T退订,给:18512345678
=====================================
使用腾讯云短信通道发送消息:测试营销类型短信 回T退订,给:18512345678

3.总结

本篇主要讲了桥接模式的概念及实现,桥接模式本身是一个很简单的设计模式,只需要掌握桥接模式的两个最重要的特点即可:

  • 通过组合/聚合进行连接,而不是继承
  • 多个维度可以独立拓展,互不影响

这两个特点其实也是对组合优于继承的一种体现,掌握这两个特点,可以在日后的开发过程中识别出桥接模式,并使用桥接模式写出高拓展性的代码。

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

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

相关文章

监听器,过滤器,拦截器

参考博文 文章目录 作用三者区别启动顺序拦截器简要说明实现接口HandlerInterceptor自定义拦截器配置拦截器 过滤器简要说明在springboot 启动类添加该注解ServletComponentScan写个过滤器类,实现Filter接口 监听器简要说明如何使用自定义事件自定义过滤器接口调用…

图片怎么转换成pdf格式?几种方法轻松转换

图片怎么转换成pdf格式?将图片转换成PDF格式的主要原因是方便共享和存储。PDF格式可以在不同的设备和操作系统上轻松打开和查看,而且可以保持原始图片的质量和分辨率。如果你需要将一些图片转换成PDF格式,你可能会问,“该如何做呢…

12个最受欢迎的3D打印机械臂【开源|DIY|套件】

推荐:用 NSDT编辑器 快速搭建可编程3D场景 机器人手臂的用途各不相同,但大多数都能够执行拾取和放置任务,而有些则配备用于 CNC 工作、激光雕刻,甚至 3D 打印。 机械臂具有广泛的应用和各个领域,从执行精密手术和进行工…

两行代码实现Redis消息队列,简单易用

Redis列表数据类型非常适合作为消息队列使用。将新的消息插入到列表尾部,然后从列表头部取出消息进行处理。该方案简单易用,并且支持多个消费者并行处理消息。 两行核心代码即可实现消息队列,如下: // 推送消息 redisTemplate.o…

Java中级编程大师班<第一篇:初识数据结构与算法-数组(2)>

数组(Array) 数组是计算机编程中最基本的数据结构之一。它是一个有序的元素集合,每个元素都可以通过索引进行访问。本文将详细介绍数组的特性、用法和注意事项。 数组的基本特性 数组具有以下基本特性: 有序性: 数…

初探词法分析实验

本次实验使用C对编译过程中的分词进行初步探究&#xff0c;以下是实验代码&#xff0c;输入文件需要在main函数中自己填写文本所在地址 #include <iostream> #include <stdlib.h> #include <stdio.h> #include<string> #define M 20 using namespace…

核心实验15_端口安全_ENSP

项目场景&#xff1a; 核心实验15_端口安全_ENSP 可指定该接口下最多接入几个设备&#xff08;通过mac绑定实现&#xff09;&#xff0c;人为增加设备时可设置接口自动down掉等&#xff0c;详见补充 实搭拓扑图&#xff1a; 具体操作&#xff1a; sw1: [Huawei]int g0/0/1 [H…

编辑视频无需第三方软件,在iPhone上也可以轻松编辑视频

如果你学会了如何在iPhone上编辑视频,你可以在很大程度上把匆忙拍摄的视频变成适合好莱坞的视频。好吧,也许这有点夸张了,但至少,你可以通过使用照片应用程序中的编辑工具,让你的视频看起来更令人印象深刻。 虽然它不一定能与最好的视频编辑软件相匹配,但它仍然非常适合…

MySQL 8.0 新密码策略的细节补充

前情提要 MySQL 8.0 截⽌到⽬前已经发布到了 8.0.34 版本&#xff0c;经过一系列的版本更新&#xff0c;对于密码方面也做了较多的加强⼯作&#xff0c;这⾥我们不再过多介绍 MySQL 8.0 对于密码功能的加强&#xff0c;相关的介绍可以移步先前公众号的⽂章&#xff0c;这⾥给到…

Pytorch 多卡并行(3)—— 使用 DDP 加速 minGPT 训练

前文 并行原理简介和 DDP 并行实践 和 使用 torchrun 进行容错处理 在简单的随机数据上演示了使用 DDP 并行加速训练的方法&#xff0c;本文考虑一个更加复杂的 GPT 类模型&#xff0c;说明如何进行 DDP 并行实战MinGPT 是 GPT 模型的一个流行的开源 PyTorch 复现项目&#xff…

paddleocr关闭log日志打印输出

问题背景 问题分析 可以看到paddleocr输出logging主要有两种&#xff0c;DEBUG和WARNING&#xff0c;因此关闭这两种打印日志即可。 解决方法 import logginglogging.disable(logging.DEBUG) # 关闭DEBUG日志的打印 logging.disable(logging.WARNING) # 关闭WARNING日志的…

Python二分查找详解

在计算机科学中&#xff0c;二分查找算法&#xff08;英语&#xff1a;binary search algorithm&#xff09;&#xff0c;也称折半搜索算法&#xff08;英语&#xff1a;half-interval search algorithm&#xff09;、对数搜索算法&#xff08;英语&#xff1a;logarithmic sea…

Pyinstaller打包EXE时添加版本信息、作者信息并在运行时读取外部配置文件

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;CSDN实力新星&#xff0c;后端开发两年经验&#xff0c;曾担任甲方技术代表&#xff0c;业余独自创办智源恩创网络科技工作室。会点点Java相关技术栈、帆软报表、低代码平台快速开…

亚马逊气候友好认证

“气候友好承诺认证”是亚马逊推出的Climate Pledge Friendly新环保计划。目的是帮助有环境意识、注重绿能的买家更好地找到带认证产品&#xff0c;品牌可以通过确保在亚马逊上销售的产品至少在可持续发展的一个方面得到认证&#xff0c;来参与并为他们的产品获得一个气候友好承…

ORA-32771 cannot add file to bigfile tablespace

ORA-32771 cannot add file to bigfile tablespace 扩容表空间报错 原因 oracle中有两种表空间类型BIGFILE 大文件表空间&#xff1a;只能包含1个大文件(最大尺寸为128 TB) SMALLFILE 小文件表空间&#xff1a;可包含多个数据文件(默认)表空间在创建的时候就会确定好&#xf…

OpenCV(三十八):二维码检测

1.二维码识别原理 功能图形&#xff1a; 位置探测图形&#xff1a;通常&#xff0c;二维码中有三个位置探测图形&#xff0c;呈现L型或大角度十字架形状&#xff0c;分布在二维码的三个角上&#xff0c;用于帮助扫描设备定位二维码的位置和方向。 位置探测图形分隔符&#xf…

2023工博会,正运动机器视觉运动控制一体机应用预览(二)

展会倒计时&#xff1a;7天 本次的中国国际工业博览会正运动技术将携高性能x86平台Windows实时视觉运动控制器VPLC711亮相。 •运动控制机器视觉一站式开发&#xff0c;缩短开发周期&#xff0c;降低硬件成本&#xff1b; •可替代传统的工控机运动控制卡/PLC视觉软件的自动化…

Fultter学习日志(2)-构建第一个flutter应用

依照上一篇中我们新建的flutter应用 让我们更改pubspec.yaml中的内容为 name: namer_app description: A new Flutter project.publish_to: none # Remove this line if you wish to publish to pub.devversion: 0.0.11environment:sdk: >2.19.4 <4.0.0dependencies:fl…

SpringBoot整合Easy-ES实现对ES操作

请确保已有可用的ES&#xff0c;若没有&#xff0c;请移步&#xff1a;Docker安装部署ElasticSearch&#xff08;ES&#xff09; 新建SpringBoot项目 这里是用的springboot版本是2.6.0 引入依赖 <!-- 排除springboot中内置的es依赖,以防和easy-es中的依赖冲突--><…

0基础学习VR全景平台篇 第99篇:百度地图如何上传全景图

蛙色平台现已打通VR全景入驻百度地图全流程&#xff0c;百度全景分为免费版和付费版两种&#xff0c;其中付费支持配置作品音乐、场景漫游热点、联系电话、描述信息。 百度地图上传案例 免费版 付费版 一、百度地图上传流程 1、进入蛙色VR账号后台 &#xff08;1&#xff…