【设计模式】适配器模式和桥接模式

news2024/11/15 4:13:12

适配器模式

适配器模式 : 就是将一个类的接口变成客户端所期望的另一种接口,使得原本因为接口不匹配而无法一起工作的接口可以正常工作。属于结构型模式

比方说我有一个A牌子的奶瓶,然后买了个B牌子的奶嘴,不能匹配怎么办? 再买一个转换器就好了

在软件开发中,基本上任何问题都可以通过加一个中间层(抽象)来解决

适配器模式一般包含三种角色 :

目标角色Target : 也就是客户端期望的接口
源角色Adaptee: 已有的接口,内容满足要求,但是客户端无法接入
适配器 Adapter:

适配器可分为三类 :类适配器,对象适配器,接口适配器 (其核心思想都是让Adapter同时具有Target和Adaptee的特性)

以生活中的的电压为例,我们需要将民用的220V的交流电转换为手机可以接收的5V的直流电

public interface IDV5VTarget {
    int output5V();
}
public class AC220VAdaptee {
    public int output220V() {
        int output = 220;
        System.out.println("输出电压:" + output + "V");
        return output;
    }
}

类适配器: 基于继承实现,Adapter继承Adaptee

public class ClassAdapter extends AC220VAdaptee implements IDV5VTarget{

    @Override
    public int output5V() {
        int output = super.output220V()/44;
        System.out.println("转换后的电压为" + output + "V");
        return output;
    }
}

对象适配器 : 基于组合实现,Adapter持有Adaptee对象

public class ObjectAdpater implements IDV5VTarget{

    private AC220VAdaptee ac220VAdaptee;

    public ObjectAdpater(AC220VAdaptee ac220VAdaptee) {
        this.ac220VAdaptee = ac220VAdaptee;
    }

    @Override
    public int output5V() {
        int output =  this.ac220VAdaptee.output220V()/44;
        System.out.println("转换后的电压为:" + output + "V");
        return output;
    }
}

接口适配器 : 如果接口定义的方法过多,通过接口适配器可以让我们只实现需要转换的方法(直接实现接口的话就会有很多空实现的方法)

总结

优点 :

  1. 通过适配器模式,客户端可以使用统一的一套接口,这样实现起来更简洁明了
  2. 复用了现有的类和代码,减少代码的改动量

使用场景

适配器模式是⽤来做适配的,它使得不兼容的接⼝转换为可兼容的接⼝,让原本由于接⼝不兼容⽽不能⼀起⼯作的类可以⼀起⼯作。常用于补偿接口设计上的缺陷。

一般使用场景如下:

  • 封装有缺陷的接⼝设计
  • 统⼀多个类的接⼝设计
  • 替换依赖的外部系统
  • 兼容⽼版本接⼝
  • 适配不同格式的数据

桥接模式

桥接模式是将抽象部分与他的具体实现分离,使其都可以独立的发生变化而互不干扰,属于结构型模式。
桥接模式的核心在于解耦抽象和实现。

这里的“抽象”,指的并⾮“抽象类”或“接⼝”,⽽是被抽象出来的⼀套“类库”,它只包含⾻架代码,真正的业务逻辑需要委派给定义中的“实现”来完成。⽽定义中的“实现”,也并⾮“接⼝的实现类”,⽽是⼀套独⽴的“类库”。“抽象”和“实现”独⽴开发,通过对象之间的组合关系,组装在⼀起

经典的桥接模式的应用就是我们的JDBC驱动

{
	Class.forName("com.mysql.jdbc.Driver");//加载及注册JDBC驱动程序
	String url = "jdbc:mysql://localhost:3306/db?
	Connection con = DriverManager.getConnection(url);
	Statement stmt = con.createStatement()String query = "select * from test_table";
	ResultSet rs=stmt.executeQuery(query);
	while(rs.next()) {
		rs.getString(1);
		rs.getInt(2);
	}
}

如果我们使用不同的数据库,只需要将com.mysql.jdbc.Driver 换成 oracle.jdbc.driver.OracleDriver 就可以了

我们可以看下jdbc是怎么实现的

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

Class.forName("com.mysql.jdbc.Driver")这里就是执行了Driver的静态代码块,将Driver注册到DriverManager里,然后我们从DriverManager里获取的connection实际是使用我们注册的driver获取到的

 public static Connection getConnection(String url,
        java.util.Properties info) throws SQLException {

        return (getConnection(url, info, Reflection.getCallerClass()));
    }

  private static Connection getConnection(
        //...
        for(DriverInfo aDriver : registeredDrivers) {
            if(isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    Connection con = aDriver.driver.connect(url, info);
                    if (con != null) {
                        // Success!
                        println("getConnection returning " + aDriver.driver.getClass().getName());
                        return (con);
                    }
                } catch (SQLException ex) {
                    if (reason == null) {
                        reason = ex;
                    }
                }
            } else {
                println("    skipping: " + aDriver.getClass().getName());
            }

        }
        throw new SQLException("No suitable driver found for "+ url, "08001");
    }

桥接模式主要包含四种角色
抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。

具体类图如下:
在这里插入图片描述
以日常工作种的告警为例,我们的告警消息可以是通过邮件,短信,电话的方式发送,根据告警的重要程度又可以分为紧急,重要,普通。告警消息可以按照发送方式和紧急程度两个不同的维度进行拆分

先定义一个发送消息的接口和一个桥接的抽象角色

public interface IMessageSender {

    void sendMessage(String message);
}

public abstract class AbstractMessage {
    private IMessageSender messageSender;

    public AbstractMessage(IMessageSender messageSender) {
        this.messageSender = messageSender;
    }

    public void sendMessage(String message) {
        this.messageSender.sendMessage(message);
    }
}
public class EmailMessageSender implements IMessageSender{

    @Override
    public void sendMessage(String message) {
        System.out.println("发送邮件"+ message + ".....");
    }
}

public class PhoneMessageSender implements IMessageSender{

    @Override
    public void sendMessage(String message) {
        System.out.println("拨打电话:" + message + ".....");
    }
}

public class SmsMessageSender implements IMessageSender{

    @Override
    public void sendMessage(String message) {
        System.out.println("发送短信" + message + ".....");
    }
}
public class NormalMessage extends AbstractMessage{

    public NormalMessage(IMessageSender messageSender) {
        super(messageSender);
    }

    @Override
    public void sendMessage(String message) {
        super.sendMessage("普通" + message);
    }
}
public class UrgencyMessage extends AbstractMessage {

    public UrgencyMessage(IMessageSender messageSender) {
        super(messageSender);
    }

    @Override
    public void sendMessage(String message) {
        super.sendMessage("紧急" + message);
    }
}

总结

桥接模式适合于以下几个场景:

  1. 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展
  2. 系统不希望使用继承或因为多层次继承导致类的个数急剧增加
  3. 需要在抽象和具体实现之间增加更多的灵活性

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

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

相关文章

Python3-输入和输出

Python3 输入和输出 输出格式美化 Python两种输出值的方式: 表达式语句和 print() 函数。 第三种方式是使用文件对象的 write() 方法,标准输出文件可以用 sys.stdout 引用。 如果你希望输出的形式更加多样,可以使用 str.format() 函数来格式化输出值。…

2020蓝桥杯真题洁净数 C语言/C++

题目描述 小明非常不喜欢数字 2,包括那些数位上包含数字 2 的数。如果一个数的数位不包含数字 2,小明将它称为洁净数。 请问在整数 1 至 n 中,洁净数有多少个? 输入描述 输入的第一行包含一个整数 n(1≤n≤10^6)。 输出描述 输…

VS Code 解决 SpringBoot 项目启动时报 Failed to refresh live data from process **** 的问题

问题 SpringBoot 启动后 ,VS Code 报错 Failed to refresh live data from process ****。 现场是,SpringBoot 项目启动时,VS Code 将进行如下刷新,图片如下所示 当刷新 10 次以后,如果还是失败,则会抛出…

C++ queue的以及优先级队列(堆)的介绍和使用

因为队列与之前学习的栈等使用方法比较类似,所以对此进行简单介绍1 queue的介绍1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。2. 队列作为容器适配器实现,容…

基于RK3588人工智能大算力5网口工业交换机

RK3588是瑞芯微旗下最新的8K旗舰SoC芯片,采用ARM架构,主要用于PC、个人移动互联网设备、边缘计算和其他数字多媒体应用。RK3588集成了四核Cortex-A76和四核Cortex-A55,以及单独的NEON协处理器,支持8K视频编解码。许多功能强大的嵌…

肠道菌群与健康:探究发酵食品、饮食方式、益生菌和后生元的影响

谷禾健康 肠道微生物群之间编织了一个复杂的相互作用网络,影响人体的营养吸收和代谢,免疫功能等,对我们的健康状态有很大的影响。 我们知道,肠道微生物群具有多样性,平衡性,稳定性等特征,但同时…

c语言面试题目整理

1、static有什么用途? 在C语言中,static主要定义全局静态变量,定义局部静态变量,定义静态函数 限制变量的作用域,设置变量的存储域。 static 关键字主要有两种作用: 第一,为某特定数据类型或对…

05 C语言数据类型

05 C语言数据类型 1、数据类型 编程语言对数据类型分为两派&#xff1a;一种认为要注重&#xff0c;一种认为可以忽视。 C语言类型 1、整数 : char < short < int < long < long long &#xff0c;bool 2、浮点数&#xff1a;float < double < long doub…

ChatGPT狂飙,文心一言会是李彦宏的“奇兵”吗?

“这是搜索领域新的一天。”前不久&#xff0c;微软CEO纳德拉在新版搜索引擎Bing的发布仪式上如此表示。Bing的技术支持&#xff0c;正是来自最近火遍全球的AI聊天机器人ChatGPT。仅仅两个月&#xff0c;OpenAI公司旗下的ChatGPT月活就超过1亿&#xff0c;成为史上增长最快的消…

Idea springboot springCloud热加载热调试常用的两种方式

场景描述 在项目开发的过程中&#xff0c;需要修改调试的时候偶每次都需要重启项目浪费时间&#xff0c;下面是我整理的两种常用的两种方式方式一 修改启动配置方式&#xff08;主要针对debug模式下&#xff09; 点击启动配置》edit configrations… configration下面修改Upd…

Win11+VS2019编译PCL1.12含gpu过程记录

之前直接用AllinOne安装了配置了一个pcl但是没有CUDA的支持&#xff0c;跑的速度很慢&#xff0c;现在想要集成到GPU上&#xff0c;需要重新编译一下PCL&#xff0c;之前自己编译一直有问题&#xff0c;而且还自己单独编译了相关的依赖库&#xff0c;结果发现只需要用AllinOne里…

《C++ Primer Plus》(第6版)第9章编程练习

《C Primer Plus》&#xff08;第6版&#xff09;第9章编程练习《C Primer Plus》&#xff08;第6版&#xff09;第9章编程练习1. 打印字符串2. 修改程序清单9.93. chaff4. sales《C Primer Plus》&#xff08;第6版&#xff09;第9章编程练习 1. 打印字符串 下面是一个头文件…

开源工具系列5:DependencyCheck

Dependency-Check 是 OWASP&#xff08;Open Web Application Security Project&#xff09;的一个实用开源程序&#xff0c;用于识别项目依赖项并检查是否存在任何已知的&#xff0c;公开披露的漏洞。 DependencyCheck 是什么 Dependency-Check 是 OWASP&#xff08;Open Web …

宿主机连接virtualbox中网络

背景&#xff1a;宿主机ubuntu&#xff0c;virtualbox中window中有VPN需要在宿主机也能共享到VPN网络。在virtualbox中添加host-only网络&#xff0c;取名vboxnet0这里在菜单栏中: 管理 -> 工具 -> network managervboxnet0在宿主的IP为192.168.56.1宿主机上运行ifconfig…

【Copula】基于二元Frank-Copula函数的风光出力场景生成方法【考虑风光出力的不确定性和相关性】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

JavaEE简单示例——依赖注入

简单介绍&#xff1a; 首先我们要知道&#xff0c;依赖注入就是赋值&#xff0c;带着这句话去理解依赖注入就非常的简单了&#xff0c;将文中所有的依赖注入全部脑部替换成给属性赋值&#xff0c;再去理解依赖注入的概念。 依赖注入&#xff08;DI&#xff09;是指IoC容器在运…

混淆矩阵的生成

混淆矩阵简介 混淆矩阵&#xff08;Confusion Matrix&#xff09;是一个二维表格&#xff0c;常用于评价分类模型的性能。在混淆矩阵中&#xff0c;每一列代表了预测值&#xff0c;每一行代表了真实值。因此&#xff0c;混淆矩阵中的每一个元素表示了一个样本被预测为某一类别…

Zabbix对接Prometheus实操——基于Prometheus pattern监控

概述 得益于对云原生和容器监控的友好支持&#xff0c;如今&#xff0c;Prometheus监控受到越来越多企业的青睐。然而&#xff0c;对于已经部署了Zabbix监控系统的企业&#xff0c;想要用Prometheus完全替换Zabbbix&#xff0c;可能既无必要&#xff0c;短期也不现实。实际上&…

Vue组件原理知识(1)

Vue 组件知识整理&#xff08;1&#xff09;文章目录Vue 组件知识整理&#xff08;1&#xff09;一、组件介绍1.1 传统方式与组件方式编写应用对比二、组件使用2.1 非单文件组件的使用**1. 组件的创建****2. 组件的注册****3. 组件的使用****4. Vue中使用组件的三大步骤总结***…

C++基础了解-20-C++类 对象

C 类 & 对象 一、C 类 & 对象 C 在 C 语言的基础上增加了面向对象编程&#xff0c;C 支持面向对象程序设计。类是 C 的核心特性&#xff0c;通常被称为用户定义的类型。 类用于指定对象的形式&#xff0c;它包含了数据表示法和用于处理数据的方法。类中的数据和方法…