首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >设计模式02——Adapter模式

设计模式02——Adapter模式

作者头像
itlemon
发布于 2020-04-03 10:06:19
发布于 2020-04-03 10:06:19
53400
代码可运行
举报
文章被收录于专栏:深入理解Java深入理解Java
运行总次数:0
代码可运行
定义

适配器设计模式,顾名思义就是将适配器的作用总结抽象成为一种代码的组织方式,将现有的代码通过适配器进行适配,以满足项目对另外一个类或者接口的要求。换句话说就是将一个类的接口适配(包装/转换)成客户(调用者)希望的另一个接口。适配器设计模式有以下两种形式:

  • 类适配器模式(使用继承的适配器)
  • 对象适配器模式(使用委托的适配器)
问题引入

我们常用的笔记本电脑的配件中就有一个适配器,负责将220V交流电转换成为12V的直流电给笔记本电脑供电,它存在的作用就是将220V交流电转换成为12V的直流电。所以它就是适配器,220V交流电就是被适配的对象,而12V直流电就是转换后的目标对象,笔记本电脑就是这个目标对象的调用者。

适配器设计模式在JDK源码中的应用

学习适配器设计模式,当然也需要从JDK中去寻找它的踪迹,在JDK源码中,采用适配器设计模式的地方很多,比如最常见的IO转换流和集合等。接下来我们一起从源码中来分析适配器设计模式是如何使用起来的。 我们一起阅读一下java.io.InputStreamReader(InputStream)的部分源码:

InputStreamReader的作用是将字节流转换为字符流,是它们之间转换的桥梁(适配器),也就是说,InputStreamReader就是适配器,负责将InputStream转换为Reader,这样就可以使用Reader的方法来执行各项操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package java.io;

import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import sun.nio.cs.StreamDecoder;

public class InputStreamReader extends Reader {

    private final StreamDecoder sd;
    
    public InputStreamReader(InputStream in) {
        super(in);
        try {
            sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
        } catch (UnsupportedEncodingException e) {
            throw new Error(e);
        }
    }
    
    public String getEncoding() {
        return sd.getEncoding();
    }

    public int read() throws IOException {
        return sd.read();
    }

    public int read(char cbuf[], int offset, int length) throws IOException {
        return sd.read(cbuf, offset, length);
    }

    public boolean ready() throws IOException {
        return sd.ready();
    }

    public void close() throws IOException {
        sd.close();
    }
}

上面的代码是经过删减后的部分代码,删除了源码中的注释以及几个构造方法,从阅读源码来看,这个适配器设计模式的形式采用的是“对象适配器模式”,至于何是“对象适配器模式”,我们将在后面的学习中介绍,读者可以暂时不必理会何是“对象适配器模式”。

手动实现适配器设计模式

接下来,我们将手动实现两种适配器设计模式,用简单的代码来说明适配器设计模式是如何运转起来的。

以前小时候都玩过QQ游戏,有时候需要充值Q币,使用Q币在游戏中购买道具,这种情景就可以完全适用适配器设计模式,那么在这种情景中,使用Q币来购买游戏道具是我们需求,也就是我们的目标(Target),而现在的现状是我们有人民币,那么人民币就是被适配的对象(Adaptee),由于人民币不能直接在游戏中购买道具,它需要被转换成Q币才可以进行交易,所以我们还需要一个适配器(Adapter),负责将人民币转换成Q币。 根据以上的文字,我们可以将其总结成为一个表格,可以很方便地理清关系:

角色

扮演者

作用

Target

购买游戏道具的接口

有充值Q币接口,有使用Q币充值游戏道具的接口

Adapter

Q币充值器

将人民币转换成为Q币,并完成充值

Adaptee

人民币

被适配,被转换的对象

根据以上的关系,我们分别来创建各个角色对应的类或者接口。这里我们模拟了使用人民币充值Q币,使用Q币购买游戏道具的案例,假设一个单位的人民币可以充值10Q币,每个Q币可以一个游戏道具。

示例代码1:类适配器设计模式(使用继承的适配器)
  • Target

我们的目标是有一个接口,这个接口可以购买游戏道具,但是需要使用Q币来进行购买。在适配器设计模式里,它是我们需要最终的目标。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.itlemon.design.pattern.chapter02.adapter.example3;

/**
 * @author jiangpingping
 * @date 2018/9/6 下午7:43
 */
public interface TargetInterface {

    /**
     * 购买qCoinCount个游戏道具
     */
    void buyGameProps();

}
  • Adaptee

现在的现状是手头上有人民币,所以需要有一个Q币充值器,将人民币换成相同价值的Q币。在适配器设计模式里面,人民币就是需要被适配的对象,因为它不能直接用来购买游戏道具,但是得必须通过它才可以充值Q币,才能满足要求。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.itlemon.design.pattern.chapter02.adapter.example3;

/**
 * 人民币
 *
 * @author jiangpingping
 * @date 2018/9/6 下午7:45
 */
public class Rmb {

    private int count;

    public Rmb(int count) {
        this.count = count;
    }

    public int getCount() {
        return this.count;
    }

}
  • Adapter

所以我们需要一个Q币充值器,将人民币换成Q币,然后还具备购买游戏道具的功能。在适配器设计模式中,Q币充值器就是我们所需的适配器。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.itlemon.design.pattern.chapter02.adapter.example3;

/**
 * Q币充值器
 *
 * @author jiangpingping
 * @date 2018/9/6 下午7:31
 */
public class QCoinRechargeableDevice extends Rmb implements TargetInterface {

    private int qCoinCount;

    public QCoinRechargeableDevice(int rmbCount) {
        super(rmbCount);
        this.qCoinCount = getCount() * 10;
    }

    @Override
    public void buyGameProps() {
        System.out.println("一共购买了" + qCoinCount + "个道具");
    }
}
  • Main

这里写一个Main方法,来验证我们上面设计的适配器设计模式,主要代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.itlemon.design.pattern.chapter02.adapter.example3;

/**
 * @author jiangpingping
 * @date 2018/9/6 下午9:26
 */
public class Main {

    public static void main(String[] args) {
        TargetInterface qCoinRechargeableDevice = new QCoinRechargeableDevice(10);
        qCoinRechargeableDevice.buyGameProps();
    }
}

这里,我们向Q币充值器充值10个单位的人民币,就可以完成购买100个游戏道具转变。本来人民币不能直接用来购买游戏道具,使用适配器设计模式之后,就可以完成我们购买游戏道具的需求。

使用继承的适配器UML类图

使用继承的适配器有一个特点就是Adapter继承了Adaptee,并实现了Target,这就是三者之间的关系。

示例代码2:对象适配器设计模式(使用委托的适配器)

这里仅仅是贴出代码,对于各个类的说明,在上面都已经进行了阐述。

  • Target
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.itlemon.design.pattern.chapter02.adapter.example4;

/**
 * @author jiangpingping
 * @date 2018/9/10 下午9:16
 */
public abstract class TargetInterface {

    /**
     * 购买qCoinCount个游戏道具
     */
    public abstract void buyGameProps();
}
  • Adaptee
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.itlemon.design.pattern.chapter02.adapter.example4;

/**
 * 人民币
 *
 * @author jiangpingping
 * @date 2018/9/6 下午7:45
 */
public class Rmb {

    private int count;

    public Rmb(int count) {
        this.count = count;
    }

    public int getCount() {
        return this.count;
    }

}
  • Adapter
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.itlemon.design.pattern.chapter02.adapter.example4;

/**
 * @author jiangpingping
 * @date 2018/9/10 下午9:18
 */
public class QCoinRechargeableDevice extends TargetInterface {

    private Rmb rmb;

    public QCoinRechargeableDevice(Rmb rmb) {
        this.rmb = rmb;
    }

    @Override
    public void buyGameProps() {
        System.out.println("一共购买了" + rmb.getCount() * 10 + "个道具");
    }
}
  • Main
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.itlemon.design.pattern.chapter02.adapter.example4;

/**
 * @author jiangpingping
 * @date 2018/9/10 下午9:16
 */
public class Main {

    public static void main(String[] args) {
        TargetInterface qCoinRechargeableDevice = new QCoinRechargeableDevice(new Rmb(10));
        qCoinRechargeableDevice.buyGameProps();
    }
}
使用委托(对象)的适配器UML类图

使用委托的适配器有一个特点就是Adapter拥有了Adaptee,并继承了Target抽象类,这就是三者之间的关系。

浅析适配器模式中的重要角色

适配器设计模式也是一个比较常用的设计模式之一,现对适配器设计模式中的角色进行浅析。

  • Target(对象) 该角色负责定义最终的需求,也就是使用适配器模式之后的最终效果。在本次示例中,TargetInterface就是扮演了这个Target角色。
  • Adaptee(被适配) 该角色定义的是原始的功能,它也许无法直接被利用,但是又不能随意更改,所以它就需要被适配,使得在不修改原始代码的情况下能激活Target的功能。在本次示例中,Rmb扮演了这个角色。
  • Adapter(适配) 该角色是适配器设计模式的核心角色,他负责适配AdapteeTarget,使得Adaptee来满足Target的需求。在本次示例中,QCoinRechargeableDevice扮演了这个角色。
  • Client(请求者) 该角色负责调用Target的方法来进行一系列的逻辑处理。在本次示例中,Main类扮演了这个角色。
适配器设计模式UML类图

分析完适配器设计模式的重要角色,当然也得理清适配器设计模式的UML类图。

  • 使用继承的适配器设计模式类图
  • 使用委托的适配器设计模式类图
为什么要使用适配器设计模式

我们往往有这种思想,要使用什么类的方法,直接使用不就OK了,或者稍微修改一下已有的代码不就可以使用了吗?其实这种思想是不正确的,因为在现有类的基础下,很多类的方法都经过了严格的测试,贸然地去修改他容易造成意外情况的发生,我们使用适配器设计模式,往往无需修改现有的代码,直接在现有的代码的基础上创建新的代码,这样即使出了错误,我们也能很快从我们新写的代码中找出端倪。使用适配器设计模式,也是对现有代码的一种重复利用。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/09/10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
设计模式(五)适配器模式Adapter(结构型)
接口的改变,是一个需要程序员们必须(虽然很不情愿)接受和处理的普遍问题。程序提供者们修改他们的代码;系统库被修正;各种程序语言以及相关库的发展和进化。
黄规速
2022/04/14
3940
设计模式(五)适配器模式Adapter(结构型)
【Java设计模式】012-适配器模式
适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。
訾博ZiBo
2025/01/06
2000
设计模式的征途—7.适配器(Adapter)模式
在现实生活中,我们的笔记本电脑的工作电压大多数都是20V,而我国的家庭用电是220V,如何让20V的笔记本电脑能够工作在220V的电压下工作?答案:引入一个电源适配器,俗称变压器,有了这个电源适配器,生活用电和笔记本电脑即可兼容。
Edison Zhou
2018/08/20
7120
设计模式的征途—7.适配器(Adapter)模式
☀️一张思维图带大家了解Java常见设计模式☀️《❤️记得收藏❤️》
设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解,本文主要列举了常用的几种设计模式。
苏州程序大白
2021/08/31
6430
☀️一张思维图带大家了解Java常见设计模式☀️《❤️记得收藏❤️》
【愚公系列】2023年11月 二十三种设计模式(六)-适配器模式(Adapter Pattern)
设计模式(Design Pattern)是软件开发领域的宝贵经验,是多人反复借鉴和广泛应用的代码设计指导。它们是一系列经过分类和归纳的代码组织方法,旨在实现可重用性、可维护性和可理解性。使用设计模式,我们能够编写高质量的代码,使其更易于他人理解,并提供了代码可靠性的保证。
愚公搬代码
2023/11/07
9240
Java | 设计模式-适配器模式
​ 在现实生活中,经常出现两个对象因接口不兼容而不能在一起工作的实例,这时需要第三者进行适配。例如,讲中文的人同讲英文的人对话时需要一个翻译,用直流电的笔记本电脑接交流电源时需要一个电源适配器,用计算机访问照相机的 SD 内存卡时需要一个读卡器等。还有像下面这张图一样:
宁在春
2022/10/31
5340
Java | 设计模式-适配器模式
【愚公系列】2021年12月 二十三种设计模式(六)-适配器模式(Adapter Pattern)
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。
愚公搬代码
2022/12/01
2440
【愚公系列】2021年12月 二十三种设计模式(六)-适配器模式(Adapter Pattern)
设计模式01——Iterator模式
迭代器(Iterator)模式,从其英文单词可以看出,有反复做某件事的意思。迭代器模式常用于数据集合中,对数据集合中的数据按照顺序进行遍历。它能提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节。
itlemon
2020/04/03
5790
设计模式01——Iterator模式
详解设计模式:适配器模式
适配器模式(Adapter Pattern)又称为变压器模式,是 GoF 的 23 种设计模式中的一种结构型设计模式。
栗筝i
2022/12/02
5520
详解设计模式:适配器模式
设计模式- 适配器模式 (Adapter Pattern)
适配器从结构上可以分为类适配器和对象适配器。其中类适配器使用继承关系来对类进行适配,而对象适配器是使用对象引用的方法来进行适配的。
易兒善
2019/05/10
5770
掌握设计模式之适配器模式
由于所在行业的需求,需要跟许多第三方系统进行接口对接,并且虽然每个系统大同小异,但每次对接开发都采用重写一套,独立维护,对接时间久了就开始考虑有什么方式能将这么多的三方系统接口接入现有系统时统一规范化,按照固定模式接入,带着这个疑惑我开始四处寻求答案。在近期参加的《Head First Design Patterns》技术读书营中,本着学习设计模式,提高编码设计能力为目的,我看到适配器模式之后,明白它就是解除我疑惑的那个答案,紧接深入学习研究,于是就有了这篇文章。那么这是个怎样的模式,以及如何使用的呢,接下来就让我们学习下吧。
闻人的技术博客
2019/09/19
6110
掌握设计模式之适配器模式
【Go实现】实践GoF的23种设计模式:适配器模式
适配器模式(Adapter)是最常用的结构型模式之一,在现实生活中,适配器模式也是处处可见,比如电源插头转换器,它可以让英式的插头工作在中式的插座上。
元闰子
2023/12/10
2950
『设计模式』适配器模式(Adapter)
适配器模式把一一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法在一起工作的两个类能够在一起工作。
风骨散人Chiam
2020/10/28
7710
「聊设计模式」之适配器模式(Adapter)
🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!
bug菌
2023/11/03
3651
「聊设计模式」之适配器模式(Adapter)
设计模式 | 适配器模式及典型应用
适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
小旋锋
2019/01/21
1.7K0
Python设计模式(7):适配器模式
在软件设计中,为了解决接口不一致的问题,两个软件模块之间往往需要通过一个适配器类 Adapter 进行“适配”。这样的模式叫做适配器设计模式。该模式可以分为两种,分别为类适配器模式(Class Adapter Pattern)和对象适配器模式(Object Adapter Pattern),如图所示。
不可言诉的深渊
2019/07/26
2K0
Java设计模式(5)适配器模式
适配器模式是一种结构型设计模式,它允许现有的接口与客户端的期望接口不匹配时协同工作。适配器模式允许一个类别的接口转化为另一个接口,从而使得原本由于接口不匹配而无法一起工作的类能够协同工作。
Jensen_97
2024/04/18
1050
Java设计模式(5)适配器模式
精读《设计模式 - Adapter 适配器模式》
Adapter(适配器模式)属于结构型模式,别名 wrapper,结构性模式关注的是如何组合类与对象,以获得更大的结构,我们平常工作大部分时间都在与这种设计模式打交道。
黄子毅
2022/03/14
3900
精读《设计模式 - Adapter 适配器模式》
Java适配器模式(adapter)
  将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
用户4919348
2019/04/02
1.1K0
Java适配器模式(adapter)
C++设计模式——Adapter适配器模式
适配器模式让特定的API接口可以适配多种场景。例如,现有一个名为"Reader()"的API接口只能解析txt格式的文件,给这个Reader()接口增加适配器以后,它可以同时支持xml、json、csv等格式的文件。
Coder-ZZ
2024/06/06
2790
C++设计模式——Adapter适配器模式
推荐阅读
相关推荐
设计模式(五)适配器模式Adapter(结构型)
更多 >
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档