我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java设计模式之适配器模式

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java设计模式之适配器模式

本文通过老王使用纸质书籍阅读小王使用电子书籍的故事,详细说明设计模式中的结构型设计模式之适配器模式,分别对对象适配器和类适配器代码实现,最后为了加深理解,会列举适配器设计模式在JDK和Spring源码中的应用。

读者可以拉取完整代码到本地进行学习,实现代码均测试通过后上传到码云,本地源码下载。

一、引出问题

自从小王被老王赶出家门以后,老王过了几天舒心的日子,在家里的书架上买了许许多多的纸质书。

有一天,小王过够了野人生活回来了,小王也是一个喜欢读书的人,但是小王不喜欢纸质书,就要求老王将这些书换成电子版。

老王立马就不开心了,这是我不知道花费多少个日夜才设计好的书架,给你换成电子版的不仅要花费我大量的精力改变原有书架的结构,再想找我想看的书得有多难,而且老李来了想看纸质版怎么办,我还要再换回去吗?

小王随即想到了一种解决思路:这些书现在符合你的风格,应该设计一种模式,让这些书也能符合我的需求,让我们俩可以在一起读书,既不改变你的书架结构,又能扩展它的功能。

老王满意的点了点头,你说的不错,这实际上就是结构型设计模式中的适配器模式。

二、概念与使用

引用Gof中对适配器设计模式的概念:将一个类的接口转化成客户希望的另一个接口,由于接口不兼容而不能一起工作的类可以一起工作。

很显然,在适配器设计模式中应该有三个角色。

目标类:Target,该角色把其他类转换为我们期望的接口,可以是一个抽象类或接口,也可以是具体类。
被适配者类(源): Adaptee ,原有的接口,也是希望被适配的接口。
适配器: Adapter, 将被适配者和目标抽象类组合到一起的类。

在我们的实际案例中,老王的纸质书很明显应该是属于被适配者,小王的电子版就是目标类,适配器应该是能调用老王的纸质书,并使用一些相关的业务方法转化成电子版,比如调用老王书之前买一个扫描仪,在老王书调出来以后扫描书籍。

既然适配器中要调用老王的纸质书,调用它的方法应该是有两种实现方式。

一是直接继承老王,那样就可以直接调用老王的方法了。

二是在适配器中创建老王的对象,然后再调用老王的方法。

这其实对应了适配器的两种方式,根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。

我们先看类适配器实现方式:

被适配者类:


public class AdapteePaperReading {

    public void readPaper(){
        System.out.println("这是老王读的纸质书...(被适配者方法)");
    }
}

目标对象:


public interface TargetOnlineReading {
    public void ReadOnline();
}

适配器:


public class Adapter extends AdapteePaperReading implements TargetOnlineReading{
    @Override
    public void ReadOnline() {

        System.out.println("买一个扫描仪...");
        readPaper();
        System.out.println("拿到纸质书扫描为电子书...");
    }
}

客户端:


public class Client {

    public static void main(String[] args) {
        Adapter adapter=new Adapter();
        adapter.ReadOnline();

    }
}

以上就实现类适配器,如果我们要实现对象适配器也很简单,目标对象和被适配者都不变,需要改变的是适配器代码


public class Adapter implements TargetOnlineReading {

    // 适配者是对象适配器的一个属性
    private AdapteePaperReading adaptee = new AdapteePaperReading();

    @Override
    public void ReadOnline() {

        System.out.println("买一个扫描仪...");
        adaptee.readPaper();
        System.out.println("拿到纸质书扫描为电子书...");
    }
}

这样老王和小王就能在一起读书了。但这种方式只能作为系统的一种补救措施,而不是在系统设计之初就考虑这种方式,如果老王有十个八个儿子都要求按照他们的习惯来,那系统就会相当的复杂,无异于一场灾难。而是应该考虑重做书架,将各种情况都考虑进去。

需要说明的是,类适配器之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

三、应用

案例有一些生硬,为了加深对适配器设计模式的把握,我们介绍该模式在Jdk源码和Spring中的应用。

1、JDK应用

JDK使用适配器的典型例子是Java线程池FutureTask类。我们知道通过实现接口实现多线程一共有两种方式,Runnable接口和Callable接口。

FutrueTask类中有两个构造方法:

构造方法一:传入参数为Callable接口

// 这是FutureTask的构造方法一
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;     
}

构造方法二:传入的参数为Runnable接口

// 这是FutureTask的构造方法二
public FutureTask(Runnable runnable, V result) {
	// 调用Executors类中的callable方法进行转化
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;   
}

在构造方法中实际上加传入的Runnable任务在内部统一被转换为Callable任务。

可以看到这里采用的是适配器模式,调用RunnableAdapter<T>(task, result)方法来适配,实现如下:

static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();
        return result;
    }
}

这样无论是传入Runnalbe还是Callable都能适配任务,这个适配器很简单,就是简单的实现了Callable接口,在call()实现中调用Runnable.run()方法,然后把传入的result作为任务的结果返回。

通过这么一个简单案例可以加深对适配器模式的理解。

2、SpringAOP应用

我们知道在Spring的Aop中,使用的 Advice(通知) 来增强被代理类的功能。

其中Advice的类型有:BeforeAdvice(在执行切点前的通知)、AfterReturningAdvice(在运行完切点完未返回之前)、ThrowsAdvice(在运行完切点时抛出异常进行的通知),AfterAdvice(执行完该切点后,进行的通知)、Around advice(包裹一个方法的执行)

在每个类型 Advice 都有对应的拦截器,MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、 ThrowsAdviceInterceptor

Spring需要将每个 Advice 都封装成对应的拦截器类型,返回给容器,这时候采用的就是适配器类型。

Advice 就相当于适配者,对应的拦截器类型就是目标类。

3、SpringMVC应用

Spring MVC中的适配器模式主要用于执行目标 Controller 中的请求处理方法。

在Spring MVC中,DispatcherServlet 作为用户,HandlerAdapter 作为期望接口,具体的适配器实现类用于对目标类进行适配,Controller 作为需要适配的类。

当Spring容器启动后,会将所有定义好的适配器对象存放在一个List集合中,当一个请求来临时,DispatcherServlet 会通过 handler 的类型找到对应适配器,并将该适配器对象返回给用户,然后就可以统一通过适配器的 hanle() 方法来调用 Controller 中的用于处理请求的方法。

通过适配器模式我们将所有的 controller 统一交给 HandlerAdapter 处理,免去了写大量的 if-else 语句对 Controller 进行判断,也更利于扩展新的 Controller 类型。

单纯的说苍白无力,我们手写实现SpringMVC的核心流程,完整代码已经上传到码云。

四、总结

既然适配器模式可以扩展原有类的功能,那它和代理模式在一定程度上不是重合了吗?貌似扩展老王的书架使用代理模式同样是可以实现。

其实我们看结构型设计模式的定义:结构型模式涉及到如何组合类和类以获得更大的结构,结构型类模式采用继承机制来组合接口或实现

代理模式与适配器模式都分别有继承、接口方式实现的子分类模式。基于接口实现的代理模式称为静态代理模式、JDK(动态)代理模式,基于继承实现的代理模式称为Cglib(动态)代理模式。

基于接口(同时含类继承)实现的适配器模式称为类适配器模式,(只)基于继承(使用委托)实现的适配器模式称为类适配器模式。

代理模式是为其他类提供一种代理以控制对这个类的访问。我们不直接去接触目标类,而是直接操作代理类,代理类再去操作目标类。因为不直接接触目标类,因此我们可以在代理类的同名方法中添加或删除功能模块,而不用去修改目标类的原方法。

而适配器模式则主要是协调现实与需求的差异,减少对已有代码的改动,适配不同的接口、类类型。

项目实施中可能会出现这样的情况:当前已完成的项目的某一个包内的各个类实现了一些特定的接口,而客户提出了新的需求,要求实现他所指定的那些接口(抛弃原有的方法或接口),但其业务细节却是相同、完全一样的。此时,我们可能并不想复制粘贴原代码到新的方法中去,这就需要将一个类的接口转换成新需求的另一个接口。

实现方式有很多,没有必要咬文嚼字纠结使用哪种设计模式,设计模式本身就是很相似,只要能简洁开发流程,让我们的代码更好的工作就是完美的。具体使用哪一种就需要读者熟练掌握各种设计模式了,并认真体会他们各自的优势。

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对编程网的支持。如果你想了解更多相关内容请查看下面相关链接

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java设计模式之适配器模式

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

java 设计模式之适配器模式的详解

java 设计模式之适配器模式的详解前言: 适配器模式(Adapter Pattern)又叫做变压器模式,也叫做包装模式。包装模式还包括装饰模式。 在计算机编程中,适配器模式(有时候也称包装样式或者包装)将一个类的接口
2023-05-31

Android设计模式之适配器(Adapter)模式

本文实例为大家分享了Android适配器模式源码,供大家参考,具体内容如下 1. 模式介绍 1.1模式的定义:适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。 1.2模式
2022-06-06

Java设计模式解析之适配器模式怎么实现

本篇内容介绍了“Java设计模式解析之适配器模式怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、什么是适配器模式:适配器模式主要用
2023-06-30

Android设计模式之适配器模式怎么使用

适配器模式是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的另一个接口。它允许不兼容的类能够一起工作,通过创建一个适配器类,将原始类的接口转换成目标接口。在Android开发中,适配器模式常用于以下场景:1. ListView和R
2023-08-14

Golang设计模式之适配器模式详细讲解

这篇文章主要介绍了使用go实现适配器模式,这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作,需要的朋友可以参考下
2023-01-11

Java设计模式的适配器模式怎么实现

这篇文章主要介绍“Java设计模式的适配器模式怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java设计模式的适配器模式怎么实现”文章能帮助大家解决问题。什么是适配器模式适配器模式(Adap
2023-06-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录