设计模式轻松学【十】适配器模式

简介: 在软件设计中也可能出现:需要开发的具有某种业务功能的组件在现有的组件库中已经存在,但它们与当前系统的接口规范不兼容,如果重新开发这些组件成本又很高,这时用适配器模式能很好地解决这些问题。

定义与特点

在现实生活中,经常出现两个对象因接口不兼容而不能在一起工作的例子,这时需要第三者进行适配。例如,讲中文的人同讲英文的人对话时需要一个翻译,用直流电的笔记本电脑接交流电源时需要一个电源适配器,用计算机访问照相机的 SD 内存卡时需要一个读卡器等。

image.png

  • 定义

    将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。适配器就是一种适配中间件,它存在于不匹配的二者之间,用于连接二者,将不匹配变得匹配。

  • 参与角色

    • Target(目标接口):当前系统业务所期待的适配器接口类,它可以是抽象类或接口。
    • Adaptee(适配者类):被适配的角色,是一个已经存在的接口,这个接口需要我们适配才能使用,适配者类提供了客户希望使用但无法直接使用的业务方法。
    • Adapter(适配器类):实现Target,作为一个转换器,对Adaptee和Target进行适配。它是适配器模式的核心。
  • 结构类图

    适配器模式分为 类适配器模式 和 对象适配器模式。

    类适配器:采用继承的方式,静态的定义,耦合度比较高,较少使用。

    对象适配器:采用对象聚合的方式,耦合度低,常用。

    1. 类适配器模式

      image.png

    2. 对象适配器模式

      image.png

  • 模式代码示例

    1. 类适配器模式的代码如下

      package com.it235.adapter.clazz;
      //目标接口,客户端所期待调用的方法
      interface Target{
          public void request();
      }
      
      //适配者接口,客户端想调用但是又无法调用的方法
      class Adaptee{
          public void specificRequest(){       
              System.out.println("适配者中的业务代码被调用!");
          }
      }
      
      //类适配器类
      class ClassAdapter extends Adaptee implements Target{
          public void request(){
              specificRequest();
          }
      }
      
      //客户端代码
      public class ClassAdapterTest{
          public static void main(String[] args){
              System.out.println("类适配器模式测试:");
              Target target = new ClassAdapter();
              target.request();
          }
      }
      //运行结果
      类适配器模式测试:
      适配者中的业务代码被调用!
    2. 对象适配器模式的代码如下

      package com.it235.adapter.object;
      
      //目标接口
      interface Target{
          public void request();
      }
      
      //适配者接口
      class Adaptee{
          public void specificRequest(){       
              System.out.println("适配者中的业务代码被调用!");
          }
      }
      
      //对象适配器类
      class ObjectAdapter implements Target{
          private Adaptee adaptee;
          public ObjectAdapter(Adaptee adaptee){
              this.adaptee = adaptee;
          }
          public void request(){
              adaptee.specificRequest();
          }
      }
      
      //客户端代码
      public class ObjectAdapterTest{
          public static void main(String[] args){
              System.out.println("对象适配器模式测试:");
              Adaptee adaptee = new Adaptee();
              Target target = new ObjectAdapter(adaptee);
              target.request();
          }
      }
      //运行结果
      对象适配器模式测试:
      适配者中的业务代码被调用!

模式实现分析

电脑通过读卡器读取TF存储卡,在智能机刚出现的时候,手机中的内存卡是可卸载的,如果要下载歌曲或者电影,我们需要拔出该存储卡之后,通过读卡器去电脑上下载,现在我们模拟电脑读取SD卡和TF内存卡之间的适配关系。

需求:电脑可以直接读取SD卡(大型一点的卡),SD卡可以充当读卡器的作用读取小的TF卡。

  1. 计算机读取SD卡程序

    interface SDCard {
        //读取SD卡方法
        String readSD();
        //写入SD卡功能
        int writeSD(String msg);
    }
    
    //华为生产的SD卡
    class HuaWeiSDCard implements SDCard {
        
        @Override
        public String readSD() {
            return "读SD卡";  
        }
        
        @Override  
        public int writeSD(String msg) {      
            System.out.println("写SD卡");    
            return 1;   
        }
    }
    
    //计算机
    class Computer {    
         public String readSD(SDCard sdCard) {        
                return sdCard.readSD();    
         }
    }
    
    //客户进行插卡操作
    public class SDCardTest {
        public static void main(String[] args) {
            Computer computer = new Computer();        
            SDCard sdCard = new HuaWeiSDCard();       
            System.out.println(computer.readSD(sdCard));    
        }
    }
    

    一般笔记本电脑都支持直接读取SD卡,但不支持读取手机中的TF小卡,这里我们让SD卡充当读卡器的作用,将TF小卡放置到SD卡上就可以完成电脑对TF小卡的读取。这里的适配器就是SD卡。

  2. 创建TF卡对象

    //TF卡接口
    interface TFCard {    
        String readTF();    
        int writeTF(String msg);
    }
    //华为TF卡
    class HuaWeiTFCard implements TFCard {    
        @Override    
        public String readTF() {        
            return "读TF卡";   
        }    
        @Override    
        public int writeTF(String msg) {        
            System.out.println("写TF卡");     
            return 1;    
        }
    }

    此时TF卡我们拿到了,但是Computer类目前只支持读SD卡,Computer已经出厂了,无法再进行卡槽扩充更改,所以我们要赋予SD卡适配器的功能,让给SD卡适配TF卡。

  3. 加入适配器,将SD支持TF卡操作

    • 类适配模式

      创建适配器类,继承了被适配类,同时实现标准接口

      //类适配模式
      class SDAdapterTF extends HuaWeiTFCard implements SDCard {
          
          @Override    
          public String readSD() {        
              System.out.println("适配读取TF卡,充当转接作用");        
              return super.readTF();    
          }    
          @Override    
          public int writeSD(String msg) {        
              System.out.println("适配写入TF卡,充当转接作用");        
              return super.writeTF(msg);    
          }
      }
      
      //客户端调用
      public class ClassAdapterTest {
          public static void main(String[] args) {
              Computer computer = new Computer();        
              SDCard tfCardAdapterSD = new SDAdapterTF();        
              System.out.println(computer.readSD(tfCardAdapterSD));    
          }
      }

      该模式基于继承实现,不利于扩展,使用比较少

    • 对象适配模式

      创建适配器类,实现标准接口,将这个调用委托给实现新接口的对象来处理

      //对象适配模式
      class SDAdapterTF implements SDCard {
          
          private TFCard tfCard;    
          
          public SDAdapterTF(TFCard tfCard) {        
              this.tfCard = tfCard;    
          }
          
          @Override    
          public String readSD() {        
              System.out.println("适配读取TF卡,充当转接作用");        
              return tfCard.readTF();    
          }    
          @Override    
          public int writeSD(String msg) {        
              System.out.println("适配写入TF卡,充当转接作用");        
              return tfCard.writeTF(msg);    
          }
      }
      
      //客户端调用
      public class ClassAdapterTest {
          public static void main(String[] args) {
              Computer computer = new Computer();
              TFCard tfCard = new HuaWeiTFCard();      
              SDCard tfCardAdapterSD = new SDAdapterTF(tfCard);        
              System.out.println(computer.readSD(tfCardAdapterSD));    
          }
      }

      对象适配模式基于组合实现,依赖较弱,扩展性强

JDK中的案例

java.util.Arrays#asList()
java.io.InputStreamReader(InputStream)
java.io.OutputStreamWriter(OutputStream)

下面以InputStreamReaderOutputStreamWriter 类为例介绍适配器模式。
InputStreamReaderOutputStreamWriter分别继承ReaderWriter两个抽象类,但是要创建它们的对象必须在构造函数中传入一个InputStreamOutputStream的实例。

InputStreamReaderOutputStreamWriter也就是将InputStreamOutputStream适配到ReaderWriter

image.png

总结

  • 优点如下。

    • 客户端通过适配器可以透明地调用目标接口。
    • 复用了现存的类,程序员不需要修改原有代码而重用现有的适配者类。
    • 将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题。

    其缺点是:对类适配器来说,更换适配器的实现过程比较复杂,过多使用会导致系统凌乱,追溯困难(内部转发导致,调用A适配成B)。

  • 适用场景

    • 系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系统的需要,甚至没有这些类的源代码。
    • 想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
目录
相关文章
|
6月前
|
设计模式 Java API
重构旧代码的秘诀:用设计模式 - 适配器模式(Adapter)给Java项目带来新生
【4月更文挑战第7天】适配器模式是解决接口不兼容问题的结构型设计模式,通过引入适配器类实现目标接口并持有不兼容类引用,实现旧代码与新接口的协作。适用于处理兼容性问题、整合遗留代码和集成第三方库。应用时,识别不兼容接口,创建适配器类转换方法调用,然后替换原有引用。注意保持适配器简单、使用组合和考虑扩展性。过度使用可能导致系统复杂和维护成本增加,应谨慎使用。
100 4
|
6月前
|
设计模式 Java 中间件
23种设计模式,适配器模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】适配器模式(Adapter Pattern)是一种结构型设计模式,它的主要目标是让原本由于接口不匹配而不能一起工作的类可以一起工作。适配器模式主要有两种形式:类适配器和对象适配器。类适配器模式通过继承来实现适配,而对象适配器模式则通过组合来实现
103 4
|
2月前
|
设计模式 Java 程序员
Java设计模式-适配器模式(8)
Java设计模式-适配器模式(8)
|
1月前
|
设计模式 Java
Java设计模式之适配器模式
这篇文章详细讲解了Java设计模式中的适配器模式,包括其应用场景、实现方式及代码示例。
41 0
|
6月前
|
设计模式 Java
【设计模式】JAVA Design Patterns——Adapter(适配器模式)
【设计模式】JAVA Design Patterns——Adapter(适配器模式)
|
2月前
|
设计模式 Java
设计模式--适配器模式 Adapter Pattern
这篇文章介绍了适配器模式,包括其基本介绍、工作原理以及类适配器模式、对象适配器模式和接口适配器模式三种实现方式。
|
3月前
|
设计模式 XML 存储
【六】设计模式~~~结构型模式~~~适配器模式(Java)
文章详细介绍了适配器模式(Adapter Pattern),这是一种结构型设计模式,用于将一个类的接口转换成客户期望的另一个接口,使原本不兼容的接口能够一起工作,提高了类的复用性和系统的灵活性。通过对象适配器和类适配器两种实现方式,展示了适配器模式的代码应用,并讨论了其优点、缺点以及适用场景。
|
5月前
|
设计模式
适配器模式-大话设计模式
适配器模式-大话设计模式
|
4月前
|
设计模式 Go 数据处理
iLogtail设计模式问题之在iLogtail中,为何需要使用适配器模式
iLogtail设计模式问题之在iLogtail中,为何需要使用适配器模式
|
4月前
|
设计模式 JavaScript 前端开发
js设计模式【详解】—— 适配器模式
js设计模式【详解】—— 适配器模式
31 0

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    42
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    46
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    54
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    62
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    57
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    41
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    106
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78