4.结构型设计模式 - 第1回:引言与适配器模式 (Adapter Pattern) ——设计模式入门系列

news2024/9/22 23:29:24

一、引言

在现代软件开发中,设计模式是帮助我们解决复杂问题的工具,它们提供了在常见场景下重用已验证解决方案的途径。而结构型设计模式主要关注类与对象之间的组合方式,旨在通过增强灵活性和降低耦合度来改进代码的结构。

本次讨论的是结构型模式中的第一个:适配器模式 (Adapter Pattern)。它的核心目的是使接口不兼容的类能够协同工作,充当两个类之间的桥梁,保证代码的可扩展性和复用性。

二、适配器模式概述

1. 定义

适配器模式(Adapter Pattern)将一个类的接口转换为客户期望的另一个接口,使得原本接口不兼容的类可以一起工作。它常用于解决“现有接口”与“需要的接口”之间的不兼容问题。

2. 使用场景

适配器模式适用于以下场景:

  • 你希望使用一个现有的类,而它的接口并不符合你的需求。
  • 创建一个可以与多个不相关类协同工作的类,而不修改这些类的接口。

三、适配器模式的结构

适配器模式可以以类适配器和对象适配器两种方式实现:

  1. 类适配器:通过继承的方式实现适配,利用多继承模拟适配。
  2. 对象适配器:通过组合(持有被适配对象的实例)实现适配。
类图:
+--------------------------------+
|           客户端(Client)      |
+--------------------------------+
            | 使用目标接口
            v
+--------------------------------+
|           目标接口(Target)   |<-----+
+--------------------------------+      |
            ^                           | 实现目标接口
            |                           |
+--------------------------------+       |
|           适配器(Adapter)    |-------+ 
| 适配器实现目标接口,并调用被适配对象 |
+--------------------------------+
            |
            v
+--------------------------------+
|        被适配者(Adaptee)     |
+--------------------------------+

四、代码实现

以下是一个简单的 Java 示例,展示如何将一个老旧的系统接口适配成新的系统接口。

1. 被适配类 (Adaptee)

// 现有类,无法直接改变
public class LegacyPrinter {
    public void printText(String text) {
        System.out.println("Legacy Printer: " + text);
    }
}

2. 目标接口 (Target)

// 客户端期望的接口
public interface Printer {
    void print(String message);
}

3. 适配器类 (Adapter)

// 通过适配器将旧的 LegacyPrinter 适配为 Printer 接口
public class PrinterAdapter implements Printer {
    private LegacyPrinter legacyPrinter;

    public PrinterAdapter(LegacyPrinter legacyPrinter) {
        this.legacyPrinter = legacyPrinter;
    }

    @Override
    public void print(String message) {
        legacyPrinter.printText(message);
    }
}

4. 客户端代码 (Client)

public class Client {
    public static void main(String[] args) {
        Printer printer = new PrinterAdapter(new LegacyPrinter());
        printer.print("Hello, Adapter Pattern!");
    }
}

五、类适配器 vs 对象适配器

适配器类型特点优缺点
类适配器通过继承实现,适配器类同时继承了目标接口和被适配者类。优点:简洁,适合单一类适配。缺点:不支持多个类适配,受限于 Java 单继承机制。
对象适配器通过组合实现,适配器类包含一个被适配者类的实例,并实现目标接口。优点:更灵活,支持多个类的适配。缺点:稍微增加了间接层次。

六、案例分析

1. 现实生活案例:电源适配器

一个常见的现实生活中的例子是电源适配器。不同国家的电压标准和插头形状不同,电器设备无法直接使用。但通过电源适配器,电压和插头形状都能被转换为设备所需的标准,从而确保设备正常工作。

2. 综合案例:数据库连接适配器

假设我们有一个旧版数据库系统,它的连接接口已经过时,但现在我们希望在新的系统中使用不同的数据库连接接口。

// 旧版数据库系统
public class OldDatabase {
    public void connectToDb(String connectionString) {
        System.out.println("Connecting to database with " + connectionString);
    }
}

// 新系统期望的数据库接口
public interface Database {
    void connect(String databaseUrl);
}

// 适配器,将老接口适配为新接口
public class DatabaseAdapter implements Database {
    private OldDatabase oldDatabase;

    public DatabaseAdapter(OldDatabase oldDatabase) {
        this.oldDatabase = oldDatabase;
    }

    @Override
    public void connect(String databaseUrl) {
        oldDatabase.connectToDb(databaseUrl);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Database db = new DatabaseAdapter(new OldDatabase());
        db.connect("jdbc:mysql://localhost:3306/mydb");
    }
}

七、补充与开发建议

在实际开发中,适配器模式是处理代码重构、引入第三方库或与遗留系统集成的有效手段。但在使用适配器时应注意以下几点:

  1. 谨慎过度使用:适配器模式容易滥用,如果系统中出现了大量的适配器类,可能预示着系统设计不够清晰。
  2. 适配的范围:当接口之间差异较大时,使用适配器可能会增加系统复杂性。最好将适配的范围控制在接口定义和调用的边界。
  3. 保持灵活性:为了保持代码的灵活性,可以结合其他模式,如工厂模式,通过工厂创建适配器实例。

八、结论

适配器模式是一种强大的模式,能够在保持原有类功能的同时,使其符合新的需求。通过合理使用,能够增强系统的兼容性和可扩展性。在架构演进和系统重构中,适配器模式是开发人员不可或缺的工具之一。


相关阅读

  • 设计模式入门系列

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

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

相关文章

Python练习宝典:Day 1 - 选择题 - 基础知识

目录 一、踏上Python之旅二、Python语言基础三、流程控制语句四、序列的应用 一、踏上Python之旅 1.想要输出 I Love Python,应该使用()函数。 A.printf() B.print() C.println() D.Print()2.Python安装成功的标志是在控制台(终端)输入python/python3后,命令提示符变为: A.&…

数业智能心大陆:职场倦怠的新解法

什么是职业倦怠&#xff1f; 在职场中&#xff0c;职业倦怠的表现形式丰富多样。从数业智能心大陆 AI 心理咨询平台的数据来看&#xff0c;职业倦怠呈现出多种状态。教师可能对教学不再满怀热情&#xff0c;精心备课也成为过去式&#xff1b;情绪上容易烦躁、易怒&#xff0c;在…

【d47_2】【Java】【力扣】1791.找出星型图的中心节点

思路 直接判断 edges[0][0] edges[0][1] edges[1][0] edges[1][1] 谁重复了 例如&#xff1a; [ [1,2] [2,3] ....],那么中心节点一定是2 代码 class Solution {public int findCenter(int[][] edges) {for (int i0;i<1;i){if (edges[1][0]edges[0][i]) {return edg…

车载软件调试工具系列---Trace32简介UI界面简介

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

java项目之常规应急物资管理系统(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的常规应急物资管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息。 项目简介&#xff1a; 基于SpringBootVue的…

TikTok流量不佳:是网络环境选择不当还是其他原因?

TikTok&#xff0c;作为全球短视频社交平台的佼佼者&#xff0c;每天都有海量的内容被上传和分享。然而&#xff0c;很多用户和内容创作者发现&#xff0c;他们的TikTok视频流量并不理想。这引发了一个问题&#xff1a;TikTok流量不佳&#xff0c;是因为网络环境选择不当&#…

S3C2440定时器

ee一、构造 二、设置相关位 1、MPLLCON寄存器&#xff08;配置MPLL寄存器&#xff0c;进行倍频&#xff09; 根据下列表格的想要输出的频率进行选择&#xff0c;选择完毕之后&#xff0c;对该寄存器进行设置 2、时钟分频控制&#xff08;CLKDIVN&#xff09;寄存器 根据不…

AD19基础应用技巧:交叉选择/跳转到器件/镜像粘贴/元器件矩形区域排列/选择过滤器/捕捉对象等设置

目录 1. 原理图<>PCB跳转2. 镜像粘贴3. 矩形区域排列4.选择过滤器5. 捕捉的对象Object for Snapping的设置 6.Grids/Guides/Axes1. **Grids&#xff08;网格&#xff09;**2. **Guides&#xff08;参考线&#xff09;**3. **Axes&#xff08;坐标轴&#xff09;**捕捉模式…

基于python的文本聚类分析与可视化实现,使用kmeans聚类,手肘法分析

1、数据预处理 由于在数据分析之前数据集通常都存在数据重复、脏数据等问题&#xff0c;所以为了提高 数据分析结果的质量&#xff0c;在应用之前就必须对数据集进行数据预处理。数据预处理的方法通常有清洗、集成、转换、规约这四个方面&#xff0c;接下来详细介绍这对爬取…

学习记录:js算法(四十二): 寻找两个正序数组的中位数

文章目录 寻找两个正序数组的中位数我的思路网上思路 总结 寻找两个正序数组的中位数 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,3], n…

力扣72-编辑距离(Java详细题解)

题目链接&#xff1a;力扣72-编辑距离 前情提要&#xff1a; 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 dp五部曲。 1.确定dp数组和i下标的含义。 2.确定递推公式。 3.dp初始化。 4.确定dp的遍历顺序。 5.如果没有ac打印dp数组 利于debug。 每一个dp…

网络层协议 —— IP协议

目录 0.前言 1.IP协议的格式 2.IP地址 2.1IP地址的划分 国际间IP地址的划分 公有IP 私有IP 特殊的IP地址 国内IP地址的划分 2.2IP地址不足问题 2.3IP地址的功能 2.4如何使用IP地址 2.5IP地址的构成 3.网段划分 以前的方案 现在的方案 4.认识宏观网络 5.路由 …

MySQL篇(事务 - 基础)

目录 一、简介 二、事务操作 1. 数据准备 2. 未控制事务 2.1. 测试正常情况 2.2. 测试异常情况 3. 控制事务 3.1. 控制事务一 查看/设置事务提交方式 提交事务 回滚事务 3.2. 控制事务二 开启事务 提交事务 回滚事务 3.3. 转账案例 四、事务的好处 五、事务四…

入门数据结构JAVA DS——二叉树的介绍 (构建,性质,基本操作等) (1)

前言 二叉树的概念和性质 二叉树的基本概念 二叉树的种类 二叉树的性质 二叉树的构建存储与遍历 存储 构建 遍历 前序遍历 后序遍历 中序遍历 层序遍历 二叉树的基本操作 获取树中结点个数 获取叶子结点个数 获取第K层结点的个数 获取二叉树的高度 检测值为v…

C++ —— vector 的模拟实现

目录 前言 1. vector深度剖析 2. 基础框架 3. 核心接口 3.1 reserve 3.2 push_back 和 pop_back 3.3 print 3.4 insert 3.5 erase 3.6 resize 4. 拷贝构造 4.1 构造与析构 4.2 拷贝构造 4.3 赋值重载 4.4 迭代器区间 5. 使用memcpy拷贝问题 前言 接:C —— 关于…

FX5 CPU模块和以太网模块的以太网通信功能

FX5 CPU模块和以太网模块的以太网通信功能的概要如下所示。 CPU模块的内置以太网端口的通信规格如下所示。 1、与MELSOFT的直接连接 不使用集线器&#xff0c;用1根以太网电缆直接连接以太网搭载模块与工程工具(GX Torks3)。无需设定IP地址&#xff0c;仅连接目标指定即可进行…

学习Java(一)类和对象

package demo.ceshi;public class Puppy {private int age;private String name;//构造器public Puppy( String name){this.name name;System.out.println("公主的名字叫&#xff1a;"name);}//设置age的值public void setAge(int age){this.age age;System.out.pr…

数值计算 --- 平方根倒数快速算法(中)

平方根倒数快速算法 --- 向Greg Walsh致敬&#xff01; 1&#xff0c;平方根倒数快速算法是如何选择初值的?WTF中的神秘数字究竟是怎么来的&#xff1f; 花开两朵&#xff0c;各表一枝。在前面的介绍中&#xff0c;我们已经知道了这段代码的作者在函数的最后使用了NR-iteratio…

CVE-2024-46103

前言 CVE-2024-46103 SEMCMS的sql漏洞。 漏洞简介 SEMCMS v4.8中&#xff0c;SEMCMS_Images.php的search参数&#xff0c;以及SEMCMS_Products.php的search参数&#xff0c;存在sql注入漏洞。 &#xff08;这个之前就有两个sql的cve&#xff0c;这次属于是捡漏了&#x1f6…

【MATLAB源码-第268期】基于simulink的永磁同步电机PMSM双闭环矢量控制系统SVPWM仿真,输出转速响应曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 永磁同步电机&#xff08;PMSM&#xff09;是目前工业领域中广泛使用的一种高效电机&#xff0c;其具有高功率密度、运行效率高、动态响应快等优点。在控制永磁同步电机时&#xff0c;通常采用矢量控制&#xff08;也称为磁场…