深入理解设计模式之适配器模式

news2025/5/25 19:13:23

深入理解设计模式之适配器模式

1. 适配器模式概述

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个类的接口转换为客户端所期望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的类能够协同工作,扮演了"转换器"的角色。

2. 适配器模式的核心组成

  • 目标接口(Target): 客户端所期望的接口
  • 适配者(Adaptee): 需要被适配的类或接口
  • 适配器(Adapter): 将适配者接口转换为目标接口的类

3. 适配器模式的类型

3.1 对象适配器

通过组合方式实现,适配器持有适配者的实例。

3.2 类适配器

通过继承方式实现,适配器同时继承适配者和实现目标接口。

4. 适配器模式实现

4.1 对象适配器实现

// 目标接口
interface MediaPlayer {
    void play(String audioType, String fileName);
}

// 适配者接口
interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

// 具体适配者实现
class VlcPlayer implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file: " + fileName);
    }

    @Override
    public void playMp4(String fileName) {
        // 不做任何事
    }
}

class Mp4Player implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        // 不做任何事
    }

    @Override
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file: " + fileName);
    }
}

// 适配器
class MediaAdapter implements MediaPlayer {
    private AdvancedMediaPlayer advancedMusicPlayer;

    public MediaAdapter(String audioType) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMusicPlayer = new VlcPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMusicPlayer = new Mp4Player();
        }
    }

    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMusicPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMusicPlayer.playMp4(fileName);
        }
    }
}

// 客户端
class AudioPlayer implements MediaPlayer {
    private MediaAdapter mediaAdapter;

    @Override
    public void play(String audioType, String fileName) {
        // 播放mp3格式音频文件的内置支持
        if (audioType.equalsIgnoreCase("mp3")) {
            System.out.println("Playing mp3 file: " + fileName);
        }
        // 通过适配器播放其他格式
        else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        } else {
            System.out.println("Invalid media. " + audioType + " format not supported");
        }
    }
}

// 测试类
public class AdapterPatternDemo {
    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();

        audioPlayer.play("mp3", "beyond_the_horizon.mp3");
        audioPlayer.play("mp4", "alone.mp4");
        audioPlayer.play("vlc", "far_far_away.vlc");
        audioPlayer.play("avi", "mind_me.avi");
    }
}

4.2 类适配器实现

// 目标接口
interface Target {
    void request();
}

// 适配者类
class Adaptee {
    public void specificRequest() {
        System.out.println("Specific request from Adaptee");
    }
}

// 类适配器
class ClassAdapter extends Adaptee implements Target {
    @Override
    public void request() {
        specificRequest(); // 调用父类方法
    }
}

// 测试类
public class ClassAdapterDemo {
    public static void main(String[] args) {
        Target target = new ClassAdapter();
        target.request();
    }
}

5. 真实世界适配器模式示例

5.1 旧系统集成案例

// 旧支付系统接口
class LegacyPaymentSystem {
    public void processPayment(String amount, String account) {
        System.out.println("Legacy payment processed: " + amount + " from account: " + account);
    }
}

// 新支付接口
interface ModernPaymentGateway {
    void processPayment(Payment payment);
}

// 支付数据传输对象
class Payment {
    private double amount;
    private String accountId;
    private String currency;
    
    public Payment(double amount, String accountId, String currency) {
        this.amount = amount;
        this.accountId = accountId;
        this.currency = currency;
    }
    
    public double getAmount() {
        return amount;
    }
    
    public String getAccountId() {
        return accountId;
    }
    
    public String getCurrency() {
        return currency;
    }
}

// 支付系统适配器
class PaymentSystemAdapter implements ModernPaymentGateway {
    private LegacyPaymentSystem legacySystem;
    
    public PaymentSystemAdapter() {
        this.legacySystem = new LegacyPaymentSystem();
    }
    
    @Override
    public void processPayment(Payment payment) {
        // 转换和适配
        String amount = payment.getAmount() + " " + payment.getCurrency();
        legacySystem.processPayment(amount, payment.getAccountId());
    }
}

// 客户端代码
public class PaymentSystemDemo {
    public static void main(String[] args) {
        // 创建新的支付请求
        Payment payment = new Payment(100.50, "ACC123456", "USD");
        
        // 使用适配器处理支付
        ModernPaymentGateway paymentGateway = new PaymentSystemAdapter();
        paymentGateway.processPayment(payment);
    }
}

5.2 第三方库集成案例

// 第三方图表库接口
class ThirdPartyChartLibrary {
    public void displayChart(String data, String type, int width, int height) {
        System.out.println("Displaying " + type + " chart with data: " + data);
        System.out.println("Dimensions: " + width + "x" + height);
    }
}

// 应用程序预期的图表接口
interface AppChartInterface {
    void drawChart(ChartData data);
}

// 图表数据
class ChartData {
    private String dataPoints;
    private ChartType type;
    private Dimension size;
    
    public ChartData(String dataPoints, ChartType type, Dimension size) {
        this.dataPoints = dataPoints;
        this.type = type;
        this.size = size;
    }
    
    public String getDataPoints() {
        return dataPoints;
    }
    
    public ChartType getType() {
        return type;
    }
    
    public Dimension getSize() {
        return size;
    }
}

// 图表类型枚举
enum ChartType {
    BAR, LINE, PIE
}

// 尺寸类
class Dimension {
    private int width;
    private int height;
    
    public Dimension(int width, int height) {
        this.width = width;
        this.height = height;
    }
    
    public int getWidth() {
        return width;
    }
    
    public int getHeight() {
        return height;
    }
}

// 图表库适配器
class ChartLibraryAdapter implements AppChartInterface {
    private ThirdPartyChartLibrary chartLibrary;
    
    public ChartLibraryAdapter() {
        this.chartLibrary = new ThirdPartyChartLibrary();
    }
    
    @Override
    public void drawChart(ChartData data) {
        // 转换数据格式
        String chartType = data.getType().toString().toLowerCase();
        chartLibrary.displayChart(
            data.getDataPoints(),
            chartType,
            data.getSize().getWidth(),
            data.getSize().getHeight()
        );
    }
}

// 客户端代码
public class ChartAdapterDemo {
    public static void main(String[] args) {
        // 创建图表数据
        ChartData barChartData = new ChartData(
            "10,25,30,40,50",
            ChartType.BAR,
            new Dimension(800, 400)
        );
        
        // 使用适配器绘制图表
        AppChartInterface chartInterface = new ChartLibraryAdapter();
        chartInterface.drawChart(barChartData);
    }
}

6. 双向适配器模式

// 接口A
interface SystemA {
    void operationA();
}

// 接口B
interface SystemB {
    void operationB();
}

// 系统A实现
class ConcreteSystemA implements SystemA {
    @Override
    public void operationA() {
        System.out.println("System A: performing operation A");
    }
}

// 系统B实现
class ConcreteSystemB implements SystemB {
    @Override
    public void operationB() {
        System.out.println("System B: performing operation B");
    }
}

// 双向适配器
class TwoWayAdapter implements SystemA, SystemB {
    private SystemA systemA;
    private SystemB systemB;
    
    public TwoWayAdapter(SystemA systemA, SystemB systemB) {
        this.systemA = systemA;
        this.systemB = systemB;
    }
    
    @Override
    public void operationA() {
        System.out.println("Adapter: redirecting operationA to operationB");
        systemB.operationB();
    }
    
    @Override
    public void operationB() {
        System.out.println("Adapter: redirecting operationB to operationA");
        systemA.operationA();
    }
}

// 测试双向适配器
public class TwoWayAdapterDemo {
    public static void main(String[] args) {
        SystemA systemA = new ConcreteSystemA();
        SystemB systemB = new ConcreteSystemB();
        
        // 创建双向适配器
        TwoWayAdapter adapter = new TwoWayAdapter(systemA, systemB);
        
        // 通过适配器调用SystemA的功能
        System.out.println("Client uses SystemA interface:");
        adapter.operationA();
        
        // 通过适配器调用SystemB的功能
        System.out.println("\nClient uses SystemB interface:");
        adapter.operationB();
    }
}

7. Java标准库中的适配器模式

Java标准库中有多处使用了适配器模式:

import java.io.*;
import java.util.*;

public class JavaAdapterExamples {
    public static void main(String[] args) {
        // 示例1: InputStreamReader作为适配器
        // InputStream(适配者) -> Reader(目标接口)
        try {
            InputStream is = new FileInputStream("file.txt");
            Reader reader = new InputStreamReader(is, "UTF-8");
            
            int data = reader.read();
            while(data != -1) {
                System.out.print((char) data);
                data = reader.read();
            }
            
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        // 示例2: Arrays.asList()作为适配器
        // 数组(适配者) -> List(目标接口)
        String[] namesArray = {"John", "Jane", "Adam"};
        List<String> namesList = Arrays.asList(namesArray);
        
        // 使用List接口的方法
        System.out.println(namesList.get(1));
        System.out.println(namesList.contains("Jane"));
        
        // 示例3: Collections.enumeration()作为适配器
        // Collection(适配者) -> Enumeration(目标接口)
        List<String> list = new ArrayList<>();
        list.add("Item 1");
        list.add("Item 2");
        
        Enumeration<String> enumeration = Collections.enumeration(list);
        while(enumeration.hasMoreElements()) {
            System.out.println(enumeration.nextElement());
        }
    }
}

8. 适配器模式的优缺点

优点

  • 解耦合: 客户端与被适配者解耦,通过目标接口进行交互
  • 复用性: 可以复用现有的类,即使接口不匹配
  • 灵活性: 可以在不修改原有代码的情况下使用已有功能
  • 开闭原则: 符合"开闭原则",不修改原有代码而扩展功能

缺点

  • 复杂性: 引入额外的类,增加系统复杂度
  • 性能开销: 可能引入额外的间接调用,影响性能
  • 可读性: 过多的适配器会使系统难以理解

9. 适配器模式的适用场景

  • 集成遗留系统: 当需要集成旧系统或第三方库时
  • 接口不兼容: 当现有接口与客户端期望的接口不兼容时
  • 类库迁移: 当迁移到新的类库但不想修改现有代码时
  • 多态接口: 当需要统一多个类的接口时

10. 适配器模式与其他模式的比较

模式适配器模式桥接模式装饰器模式代理模式
意图使不兼容接口兼容将抽象与实现分离动态添加功能控制对象访问
结构转换接口分离层次结构包装对象包装对象
侧重点接口转换接口与实现分离功能扩展访问控制

11. 总结

适配器模式是一种强大的结构型设计模式,用于解决接口不兼容问题。它在系统集成、类库迁移和接口统一等场景中非常有用。通过将一个类的接口转换为客户端期望的另一个接口,适配器让原本不兼容的类能够协同工作。

适配器模式的两种主要实现方式——对象适配器和类适配器,为不同场景提供了灵活的解决方案。在实际开发中,对象适配器因其更高的灵活性和更低的耦合度而被更广泛使用。

适当使用适配器模式可以大大提高代码的可维护性和可扩展性,特别是在处理遗留系统和第三方库集成时。但也应注意避免过度使用适配器,以免增加系统的复杂性。

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

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

相关文章

产业互联网+三融战略:重构企业增长密码

产业互联网时代&#xff1a;用"三融"重构企业增长飞轮 在产业互联网浪潮下&#xff0c;企业面临资源分散、资金短缺、人才难聚的三重挑战。本文提出的"融人、融资、融资源"顶层设计&#xff0c;正为新时代企业构建增长新引擎。 一、三级合伙人体系&#x…

Centos系统资源镜像配置

主要体现 yum 命令执行报错&#xff0c;排除网络连接问题 解决步骤&#xff1a; 下载安装工具 # 安装 wget curl vim yum install -y wget curl vim 原有repo文件备份 # 进入配置文件所在文件夹 cd /etc/yum.repos.d# 创建 backup 文件夹 mkdir backup# 备份文件放置文件夹 m…

【Linux网络篇】:Socket网络套接字以及简单的UDP网络程序编写

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;Linux篇–CSDN博客 文章目录 网络编程套接字一.预备知识1.理解源IP地址和目的IP地址2.认识端…

学习路之uniapp--unipush2.0推送功能--给自己发通知

学习路之uniapp--unipush2.0推送功能--给自己发通知 一、绑定云空间及创建云函数二、编写发送界面三、效果后期展望&#xff1a; 一、绑定云空间及创建云函数 package.json {"name": "server-push","dependencies": {},"main": "…

leetcode hot100刷题日记——12.反转链表

解答&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(n…

《Python语言程序设计》第4章第8题3个个位数之间比大小。‘a小于b而b大于c’这是最有漏洞的一个对比,请问我如何判断a和c

升序来做这个题 比如123就变成321 需要比对3个数 这不是比对2个数。a和b比对 我们可以直接写 if a>b: print(ab) else print(ba) 但是现在是3个数abc 如果进行if比对呢 if a > b >c: print(a,b,c) elif a < b >c: print(bca) … 简洁的代码变成了复杂的代码段。…

Selenium 测试框架 - Python

🚀Selenium Python 实战指南:从入门到进阶 Selenium 是 Web 自动化测试中最受欢迎的工具之一,支持多种浏览器和语言。本文将从环境搭建到多浏览器兼容、测试框架集成、元素定位方式、常用操作、浏览器配置等多个方面进行详细讲解,并分享常见的最佳实践建议。 📦一、环境…

RNN GRU LSTM 模型理解

一、RNN 1. 在RNN中&#xff0c; 二、GRU 1. GRU是为了解决RNN 梯度消失引入的改良模型&#xff0c; 2. GRU 通过门控 Gamma_r Gamma_u 两个变量&#xff0c;实现了对于过往记忆的筛选&#xff1a;这种机制使得GRU能够灵活地决定何时“忘记”过去的信息以及何时“记住”新的…

【MC】红石比较器

在《我的世界》&#xff08;Minecraft&#xff09;中&#xff0c;红石比较器&#xff08;Redstone Comparator&#xff09; 是一种高级红石元件&#xff0c;主要用于 检测、比较或处理信号强度&#xff0c;同时还能与容器、特定方块互动。 红石比较器有两种模式&#xff1a; 比…

红黑树简单模拟实现

定义成员变量旋转insert以234树的角度来待插入操作具体代码 完整代码 我们前面实现了 二叉搜索树和 AVL树。 其中AVL树是二叉搜索树的改进&#xff0c;但是有些人觉得二叉树搜索的插入调整太频繁了&#xff0c;或者说平衡条件过于苛刻。 于是人们放松了左右子树高度差的限制&…

豪越科技:消防应急装备智能仓储管理新变革

在消防救援工作中&#xff0c;消防装备无疑是消防员们与火灾等灾害顽强对抗的关键“武器”。然而&#xff0c;传统的消防装备管理模式长期以来饱受诸多痛点的困扰&#xff0c;严重影响着消防工作的高效开展和救援效果。 在过去&#xff0c;装备丢失的情况时有发生。由于缺乏有效…

如何设计Agent的记忆系统

最近看了一张画Agent记忆分类的图 我觉得分类分的还可以&#xff0c;但是太浅了&#xff0c;于是就着它的逻辑&#xff0c;仔细得写了一下在不同的记忆层&#xff0c;该如何设计和选型 先从流程&#xff0c;作用&#xff0c;实力和持续时间的这4个维度来解释一下这几种记忆&am…

毕业论文格式(Word)

目录 Word目录怎么自动生成&#xff1f;快速生成试试这3个方法&#xff01; - 知乎https://zhuanlan.zhihu.com/p/692056836目录生成需要先设置标题样式&#xff0c;这个不仅是目录生成需要&#xff0c;和后续的图表也有关系。 最好不要自己创建新的样式&#xff0c;而是在现有…

学习STC51单片机14(芯片为STC89C52RC)

接下来我们进入学会了HC—SR04 还有舵机那么现在我们将他们融合在一起&#xff0c;用超声波来引导舵机的转动 我们这个最后的成果是做一个智能垃圾桶 成品是这样的&#xff0c;是不是可有意思了 成品视频 现在我们将舵机的代码和超声波测距模块的代码整合到一起&#xff0c;实…

基于CodeBuddy实现本地网速的实时浏览小工具

本文所使用的 CodeBuddy 免费下载链接&#xff1a;腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 前言 在数字化浪潮席卷全球的今天&#xff0c;网络已成为人们生活和工作中不可或缺的基础设施。无论是在线办公、学习、娱乐&#xff0c;还是进行大数据传输和云计算&…

stable diffusion论文解读

High-Resolution Image Synthesis with Latent Diffusion Models 论文背景 LDM是Stable Diffusion模型的奠基性论文 于2022年6月在CVPR上发表 传统生成模型具有局限性&#xff1a; 扩散模型&#xff08;DM&#xff09;通过逐步去噪生成图像&#xff0c;质量优于GAN&#x…

计算机网络(3)——传输层

1.概述 1.1 传输层的服务和协议 (1)传输层为允许在不同主机(Host)上的进程提供了一种逻辑通信机制 (2)端系统(如手机、电脑)运行传输层协议 发送方&#xff1a;将来自应用层的消息进行封装并向下提交给 网络层接收方&#xff1a;将接收到的Segment进行组装并向上提交给应用层 …

LangChain构建RAG的对话应用

目录 Langchain是什么&#xff1f; LangSmith是什么&#xff1f; ​编辑 使用Python构建并使用AI大模型 数据解析器 提示模版 部署 记忆功能 Chat History -- 记忆 代码执行流程&#xff1a; 流式输出 构建向量数据库和检索器 检索器 代码执行流程 LLM使用检索器…

目标检测DN-DETR(2022)详细解读

文章目录 gt labels 和gt boxes加噪query的构造attention maskIS&#xff08;InStability&#xff09;指标 在DAB-Detr的基础上&#xff0c;进一步分析了Detr收敛速度慢的原因&#xff1a;二分图匹配的不稳定性&#xff08;也就是说它的目标在频繁地切换&#xff0c;特别是在训…

嵌入式培训之系统编程(四)进程

一、进程的基本概念 &#xff08;一&#xff09;定义 进程是一个程序执行的过程&#xff08;也可以说是正在运行的程序&#xff09;&#xff0c;会去分配内存资 源&#xff0c;cpu的调度&#xff0c;它是并发的 &#xff08;二&#xff09;PCB块 1、PCB是一个结构体&#x…