吴志勇的博客 吴志勇的博客
  • h5

    • HTML5&CSS3
  • scss

    • css预处理语言
  • JavaScript

    • JavaScript教程
    • Ajax
    • ES6教程
    • NodeJS
    • Typescript
  • 框架

    • Jquery
    • VUE
    • React
  • Swing专题
  • java基础
  • javaweb
  • 框架
  • 数据库
  • netty
  • 设计模式
  • 微服务及架构
  • 云原生
  • maven
  • 单元测试
工具
我的
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

吴志勇

......
  • h5

    • HTML5&CSS3
  • scss

    • css预处理语言
  • JavaScript

    • JavaScript教程
    • Ajax
    • ES6教程
    • NodeJS
    • Typescript
  • 框架

    • Jquery
    • VUE
    • React
  • Swing专题
  • java基础
  • javaweb
  • 框架
  • 数据库
  • netty
  • 设计模式
  • 微服务及架构
  • 云原生
  • maven
  • 单元测试
工具
我的
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Swing专题

  • java基础

  • javaweb

  • 框架

  • Maven
  • 单元测试
  • 动态代理
  • 数据库

  • netty

  • 设计模式

    • simple_factory
    • factory_method
    • abstract_factory
    • singleton
    • builder
    • prototype
    • adapter
      • 模式引入
        • 问题描述
        • 模式定义
        • 问题分析
      • 模式介绍
        • 解决方案
        • 代码实现
        • 结构组成
      • 模式评价
        • 适用场景
        • 实际应用
        • 优点缺点
    • decorator
    • facade
    • bridge
    • proxy
    • composite
    • flyweight
    • observer
    • command
    • state
    • chain_of_responsibility
    • template_method
    • strategy
    • interpreter
    • mediator
    • visitor
    • memento
    • iterator
  • 微服务及架构

  • 云原生

  • Velocity模板引擎
  • 后端
  • 设计模式
wuzhiyong
2025-01-13

adapter

# 适配器模式

# 模式引入

# 问题描述

想象我们要出国旅游,到了异国他乡不懂当地语言怎么办?路上卯足马力突击学习?当然可以!不过更简单的做法是,打开手机翻译软件,切换到「当地语言-中文」就可以借助它与当地人进行对话了。这样,只要我们手机里有其他语言与中文的互译,就可以走遍地球任意一个角落并和当地人沟通了,而且我们自己并不需要真正掌握任何一门外语。

当然,有时候用翻译软件有点麻烦,有不准确的情况。此时,可以在当地找一个翻译,比如领导人出访国外时会带一个翻译,刚去 NBA 打球的姚明也随时有一个翻译在身边。

# 模式定义

这就是适配器模式,它一般在有满足需求功能的类,但接口不符合要求,或者希望创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作时出现。总的来说,它的主要目的是希望能复用已有的类,但接口又与复用环境要求不一致。

适配器模式是将一个类的接口转换成客户希望的另外一个接口。使得原来接口不兼容的类可以一起工作。

# 问题分析

上面的例子中,中文与其他语言的互译器以及翻译人员就是适配器,我们自己或姚明就是那个已有的满足功能的类,接口和环境就是异国他乡。

# 模式介绍

# 解决方案

  • 定义抽象类:Player,以及方法 attact 和 defense。
  • 实现具体类:Forwards、Center 和 Guards 等,并重写抽象方法。
  • 定义需要适配的类:ForeignCenter,他的方法和抽象类的不一样,需要适配。
  • 使用适配器:Translator 将需要适配的 ForeignCenter 转换为 Player。

下面是一些注意事项:

  • 一般在开发后期或维护期,双方都比较稳定、不太容易修改时候才会使用。

# 代码实现

Target 抽象类:

public abstract class Player {
    protected String name;
    public Player(String name) {
        this.name = name;
    }

    public abstract void attack();
    public abstract void defense();
}
1
2
3
4
5
6
7
8
9

Target 具体类:

public class Forwards extends Player {
    public Forwards(String name) {
        super(name);
    }

    @Override
    public void attack() {
        System.out.println("前锋 " + name + " 进攻");
    }

    @Override
    public void defense() {
        System.out.println("前锋 " + name + " 防守");
    }
}

public class Center extends Player {
    public Center(String name) {
        super(name);
    }

    @Override
    public void attack() {
        System.out.println("中锋 " + name + " 进攻");
    }

    @Override
    public void defense() {
        System.out.println("中锋 " + name + " 防守");
    }
}

public class Guards extends Player {
    public Guards(String name) {
        super(name);
    }

    @Override
    public void attack() {
        System.out.println("后卫 " + name + " 进攻");
    }

    @Override
    public void defense() {
        System.out.println("后卫 " + name + " 防守");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

Adaptee 类:

public class ForeignCenter {
    private String name;
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void attack() {
        System.out.println("外籍中锋 " + name + " 进攻");
    }

    public void defense() {
        System.out.println("外籍中锋 " + name + " 防守");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Adapter 类:

public class Translator extends Player {
    private ForeignCenter wjzf = new ForeignCenter();

    public Translator(String name) {
        super(name);
        wjzf.setName(name);
    }

    @Override
    public void attack() {
        wjzf.attack();
    }

    @Override
    public void defense() {
        wjzf.defense();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Main 方法:

public class Main {
    public static void main(String[] args) {
        Player b = new Forwards("巴蒂尔");
        b.attack();

        Player m = new Guards("麦克格雷迪");
        m.attack();

        Player ym = new Translator("姚明");
        ym.attack();
        ym.defense();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

执行结果:

前锋 巴蒂尔 进攻
后卫 麦克格雷迪 进攻
外籍中锋 姚明 进攻
外籍中锋 姚明 防守
1
2
3
4

# 结构组成

  • Target:客户所期待的接口,可以是具体类、抽象类或接口。
  • Adaptee:需要适配的类。
  • Adapter:通过在内部包装一个 Adaptee 对象,把源接口转换为目标接口。

# 模式评价

# 适用场景

  • 系统数据和行为正确,但接口不符时。比如上面姚明他听不懂英文的进攻和防守。
  • 扩展新功能接入第三方接口时。

# 实际应用

实际中的例子:复用功能但接口不符,俗称包一层。

# 优点缺点

适配模式优点包括:

  • 接口与业务逻辑解耦。Adapter 只要和 Target 对齐就行,Client 根本不关心 Adaptee 具体怎么和 Adapter 对接,它甚至不需要知道 Adaptee 的存在。
  • 容易扩展。

适配模式缺点包括:

  • 代码复杂度增加。
上次更新: 2025-02-06 00:56:14

← prototype decorator→

Copyright © 2020-2025 wuzhiyong
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式