设计模式基础概念(结构型模式):适配器模式(Adapter Pattern)

概述

适配器模式是一种结构型设计模式, 它能使接口不兼容的对象能够相互合作

适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至察觉不到适配器的存在

例如, 你可以使用一个将所有数据转换为英制单位 (如英尺和英里) 的适配器封装运行于米和千米单位制中的对象。

适配器不仅可以转换不同格式的数据, 其还有助于采用不同接口的对象之间的合作

它的运作方式如下:

  • 适配器实现与其中一个现有对象兼容的接口。
  • 现有对象可以使用该接口安全地调用适配器方法。
  • 适配器方法被调用后将以另一个对象兼容的格式和顺序将请求传递给该对象
  • 有时你甚至可以创建一个双向适配器来实现双向转换调用

结构

对象适配器

实现时使用了构成原则适配器实现了其中一个对象的接口, 并对另一个对象进行封装

所有流行的编程语言都可以实现适配器。

类适配器

这一实现使用了继承机制: 适配器同时继承两个对象的接口。

请注意, 这种方式仅能在支持多重继承的编程语言中实现, 例如 C++

java现有示例及识别方法

使用示例: 适配器模式在 Java 代码中很常见。 基于一些遗留代码的系统常常会使用该模式 。 在这种情况下, 适配器让遗留代码与现代的类得以相互合作。

Java 核心程序库中有一些标准的适配器:

  • java.util.Arrays#asList()
  • java.util.Collections#list()
  • java.util.Collections#enumeration()
  • java.io.InputStreamReader(InputStream) (返回 Reader对象)
  • java.io.OutputStreamWriter(OutputStream) (返回 Writer对象)
  • javax.xml.bind.annotation.adapters.XmlAdapter#marshal() 和 #unmarshal()

识别方法 : 适配器可以通过以不同抽象或接口类型实例为参数的构造函数来识别 。 当适配器的任何方法被调用时, 它会将参数转换为合适的格式, 然后将调用定向到其封装对象中的一个或多个方法。

伪代码实现

客户端接口 (Client Interface)

客户端接口 (Client Interface) 描述了其他类与客户端代码合作时必须遵循的协议

定义用户实际需要的接口

java 复制代码
abstract class Target {
    public abstract void Request();
}

服务 (Service)

服务 (Service) 中有一些功能类 (通常来自第三方或遗留系统)。 客户端与其接口不兼容, 因此无法直接调用其功能

定义一个需要适配的接口

java 复制代码
class Adaptee {
    public void SpecificRequest() {
        System.out.println("特殊请求");
    }
}

适配器 (Adapter)

适配器 (Adapter) 是一个可以同时与客户端和服务交互的类 :它在实现客户端接口的同时封装了服务对象

适配器接受客户端通过适配器接口发起的调用, 并将其转换为适用于被封装服务对象的调用

通过在内部包装一个 Adaptee 对象,把源接口转换成目标接口。

java 复制代码
class Adapter extends Target {
	// 在适配器类中添加一个成员变量用于保存对于服务对象的引用
    private Adaptee adaptee = new Adaptee();
	// 依次实现适配器类客户端接口的所有方法
    @Override
    public void Request() {
        adaptee.SpecificRequest();
    }
}

客户端 (Client)

java 复制代码
public class AdapterPattern {
    public static void main(String[] args) {
        Target target = new Adapter();
        // 客户端必须通过客户端接口使用适配
        target.Request();
    }
}

示例2

将两种完全不同的事物联系到⼀起,就像现实⽣活中的变压器。

假设⼀个⼿机充电器需要的电压是20V,但是正常的电压是 220V,这时候就需要⼀个变压器,

将220V的电压转换成20V的电压,这样,变压器就将20V的电压和⼿机联系起来了。

适配器

java 复制代码
class VoltageAdapter {
    public void changeVoltage() {
        System.out.println("正在充电...");
        System.out.println("原始电压:" + Phone.V + "V");
        System.out.println("经过变压器转换之后的电压:" + (Phone.V - 200) + "V");
    }
}

适配器接受客户端通过适配器接口发起的调用, 并将其转换为适用于被封装服务对象的调用

java 复制代码
class Phone {
    public static final int V = 220;
    private VoltageAdapter adapter;

    public void charge() {
        adapter.changeVoltage();
    }

    public void setAdapter(VoltageAdapter adapter) {
        this.adapter = adapter;
    }
}
java 复制代码
public class Test {
    public static void main(String[] args) {
        Phone phone = new Phone();
        VoltageAdapter adapter = new VoltageAdapter();
        phone.setAdapter(adapter);
        phone.charge();
    }
}

实现方式

  1. 确保至少有两个类的接口不兼容

    一个无法修改 (通常是第三方、 遗留系统或者存在众多已有依赖的类) 的功能性服务类
    一个或多个将受益于使用服务类的客户端类

  2. 声明客户端接口, 描述客户端如何与服务交互。

  3. 创建遵循客户端接口的适配器类。 所有方法暂时都为空。

  4. 在适配器类中添加一个成员变量用于保存对于服务对象的引用

    1. 通常情况下会通过构造函数对该成员变量进行初始化, 但有时在调用其方法时将该变量传递给适配器会更方便。
    2. 依次实现适配器类客户端接口的所有方法。 适配器会将实际工作委派给服务对象, 自身只负责接口或数据格式的转换。
  5. 客户端必须通过客户端接口使用适配器。 这样一来, 你就可以在不影响客户端代码的情况下修改或扩展适配器。

相关推荐
☼←安于亥时→❦3 小时前
PyTorch 梯度与微积分
人工智能·pytorch·python
程序员三藏4 小时前
2025最新的软件测试面试八股文(800+道题)
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展
Pocker_Spades_A4 小时前
Python快速入门专业版(二十三):for循环基础:遍历字符串、列表与range()函数(计数案例)
python
闲人编程4 小时前
图像去雾算法:从物理模型到深度学习实现
图像处理·人工智能·python·深度学习·算法·计算机视觉·去雾
Kyln.Wu5 小时前
【python实用小脚本-211】[硬件互联] 桌面壁纸×Python梦幻联动|用10行代码实现“开机盲盒”自动化改造实录(建议收藏)
开发语言·python·自动化
Ms_Big6 小时前
ppliteseg改rknn,部署在嵌入式板,加速模型
人工智能·python·深度学习
折翼的恶魔7 小时前
数据分析:合并
python·数据分析·pandas
百锦再7 小时前
在 CentOS 系统上实现定时执行 Python 邮件发送任务
java·linux·开发语言·人工智能·python·centos·pygame
I'm a winner7 小时前
第五章:Python 数据结构:列表、元组与字典(二)
数据结构·python
番薯大佬7 小时前
Python学习-day8 元组tuple
java·python·学习