适配器模式——合二为一

3,919 阅读4分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战


哈喽,大家好,我是一条~

设计模式,虽迟但到。

对设计模式不是很熟悉的同学可以先看一下《23种设计模式的一句话通俗解读》全面的了解一下设计模式,形成一个整体的框架,再逐个击破。

往期回顾设计模式合集

今天我们一块看一下适配者模式,属于结构型模式

导图

定义

官方定义

一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

通俗解读

两个不兼容接口之间适配的桥梁,做法是将类自己的接口包裹在一个已存在的类中。

分为结构型模式(继承)和对象结构型模式(组合)两种。

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

结构图

适配器模式包含以下主要角色:

  • 目标接口:可以是抽象类或接口。客户希望直接用的接口
  • 适配者类:隐藏的转换接口
  • 适配器类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口。

代码演示

目录结构

建议跟着一条学设计模式的小伙伴都建一个maven 工程,并安装lombok依赖和插件。

并建立如下包目录,便于归纳整理。

pom如下

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.10</version>
    </dependency>

开发场景

相信大家都有看美剧或者看好莱坞电影的经历,画面确实精美震撼,但语言也是很多人的一大难关,多亏有字幕,有人喜欢中英对照,也有人喜欢只看中文。英文好的当我没说。

就是这样一个场景,现有一个播放器接口和一个翻译接口,上面的功能该如何实现呢?

代码实现

中国人不骗中国人,以下代码全部亲自运行验证过。

前期准备

新建两个接口和实现类。

Player

public interface Player {
  public String play();  
}

Translater

public interface Translater {
    String translate(String content);
}

MoviePlayer

public class MoviePlayer implements Player{
    @Override
    public String play() {
        System.out.println("播放画面:一条的2021");
        String words="hello";
        System.out.println("字幕:hello");
        return words;
    }
}

En_ChTranslater

public class En_ChTranslater implements Translater{

    @Override
    public String translate(String content) {
        // 省略业务代码
        return "你好";
    }
}

新建测试类:MainTest

public class MainTest {
    // 适配器模式测试类
    public static void main(String[] args) {
        // 0.正常模式
        // 创建播放器
        MoviePlayer player = new MoviePlayer();
        String words = player.play();
        // 创建翻译器,并翻译字幕
        En_ChTranslater translater = new En_ChTranslater();
        String translate = translater.translate(words);
        System.out.println("翻译:"+translate);
    }
}

输出结果

以上虽然实现了功能,但是如果想多次使用播放并翻译的功能代码会比较冗余,有同学说可以提取出一个方法,没问题,那我如果想对翻译功能做一些修改呢,比如某些隐私信息不翻译,又不能修改原有接口?

怎么办呢?这就是适配器模式解决的问题。

类模式

新建适配器接口:PlayerAdapter

public interface PlayerAdapter {
    void playAndTranslate();
}

实现适配器接口:MoviePlayerAdapter

public class MoviePlayerAdapter extends En_ChTranslater implements PlayerAdapter{

    private MoviePlayer moviePlayer;

    public MoviePlayerAdapter(MoviePlayer moviePlayer) {
        this.moviePlayer = moviePlayer;
    }

    @Override
    public void playAndTranslate() {
        String words = moviePlayer.play();
        String translate = translate(words);
        System.out.println("翻译:"+translate);
    }
}

编写测试类

public class MainTest {
    // 适配器模式测试类
    public static void main(String[] args) {
        // 1.类结构模式——继承实现
        MoviePlayerAdapter adapter = new MoviePlayerAdapter(new MoviePlayer());
        adapter.playAndTranslate();
    }
}

输出结果:

对象模式

类模式是用继承的方式实现,对象用组合的方式,什么是组合呢?即用构造器注入或者作为全局变量new出来。

修改适配器类

public class MoviePlayerAdapter  implements PlayerAdapter{

    private final MoviePlayer moviePlayer;
    private final En_ChTranslater translator =new En_ChTranslater();

    public MoviePlayerAdapter(MoviePlayer moviePlayer) {
        this.moviePlayer = moviePlayer;
    }

    @Override
    public void playAndTranslate() {
        String words = moviePlayer.play();
        String translate = translator.translate(words);
        System.out.println("翻译:"+translate);
    }
}

输出结果

应用场景

  • Tomcat如何将Request流转为标准Request
  • Spring AOP中的AdvisorAdapter是什么
  • Spring MVC中经典的HandlerAdapter是什么
  • SpringBoot 中 WebMvcConfigurerAdapter为什么存在又取消

总结

适配器模式试用于“代码补偿”。在想创建一个可以重复使用的类,现有的类又无法满足时,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构。

增加了类的透明性和复用性,灵活性和扩展性都非常好,完全符合“开闭原则”。


最后,如果文章对你有帮助。

记得给文章点个赞呀!