07-适配器模式

参考资料1:http://c.biancheng.net/design_pattern/

参考资料2:https://refactoringguru.cn/design-patterns/catalog

适配器模式类图

1. 介绍

1.1 简介

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁

属于结构型模式,它结合了两个独立接口的功能。

适配器模式通过定义一个新的接口(对要实现的功能加以抽象),和一个实现该接口的Adapter(适配器)类来透明地调用外部组件。这样替换外部组件时,最多只要修改几个Adapter类就可以了,其他源代码都不会受到影响。

适配器模式有两种形式,一种是类的适配,另一种自然就是对象的适配。

以手机为例子:

每一种机型都自带有充电器,有一天自带充电器坏了,而且市场没有这类型充电器可买了,怎么办?

万能充电器就可以解决,这个万能充电器就是适配器。

1.2 优缺

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

  2. 主要解决
    主要解决在软件系统中,常常要将一些”现存的对象”放到新的环境中,而新环境要求的接口是现对象不能满足的。

  3. 何时使用

  • 系统需要使用现有的类,而此类的接口不符合系统的需要。

  • 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。

    • 通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)
  1. 如何解决
    继承或依赖(推荐)。

  2. 关键代码
    适配器继承或依赖已有的对象,实现想要的目标接口。

  3. 优点:

    • 可以让任何两个没有关联的类一起运行。
    • 提高了类的复用。
    • 增加了类的透明度。
    • 灵活性好。
  4. 缺点:

    • 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
    • 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

1.3 适配方式

  • 类的适配
    • 目标(Target)角色:这就是所期待得到的接口。注意:由于这里讨论的是类适配器模式,因此目标不可以是类。
    • 源(Adapee)角色:现在需要适配的接口。
    • 适配器(Adaper)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。
  • 对象的适配
    • 对象的适配依赖于对象的组合,而不是类适配中的继承。

2. 实现

2.1 类的适配

情景:手机充电用 手机充电器 充电,耳机用 耳机充电器 充电,现在要实现给手机充电的同时也能给耳机充电。

类的适配

充电器接口:

1
2
3
4
5
6
7
8
9
/**
* @Interface: ICharge
* @Description: 充电器接口
* @Author: Jerry(姜源)
* @Create: 20/09/12 12:53
*/
public interface ICharge {
void charge();
}

手机充电器类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import com.demo.designmode.adapter.ICharge;

/**
* @Class: AppleChargerIChargeImpl
* @Description: 苹果手机充电器需要适配的角色(Adapee)
* @Author: Jerry(姜源)
* @Create: 20/09/12 12:54
*/
public class AppleChargerIChargeImpl implements ICharge {
@Override
public void charge() {
System.out.println("苹果手机正在充电...");
}
}

适配器接口:

1
2
3
4
5
6
7
8
9
10
/**
* @Interface: IChargeAdapter
* @Description: 要对这个特殊的充电器进行适配, 适配器接口(Target角色)
* @Author: Jerry(姜源)
* @Create: 20/09/12 12:56
*/
public interface IChargeAdapter {
void charge();
}

类的适配器类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import com.demo.designmode.adapter.impl.AppleChargerIChargeImpl;

/**
* @Class: MultipleJointsCharger
* @Description: 多接头充电器,支持一边充手机,一边充耳机(Adaper)
* @Author: Jerry(姜源)
* @Create: 20/09/12 13:03
*/
public class MultipleJointsCharger extends AppleChargerIChargeImpl implements IChargeAdapter {
@Override
public void charge() {
super.charge();
System.out.println("耳机正在充电...");
}
}

启动类:

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @Class: MainClass
* @Description: 启动类
* @Author: Jerry(姜源)
* @Create: 20/09/12 13:04
*/
public class StartClass {
public static void main(String[] args) {
MultipleJointsCharger mc = new MultipleJointsCharger();
mc.charge();
}
}

image-20200912131135353

2.2 对象的适配

对象的适配

充电器接口:

1
2
3
4
5
6
7
8
9
/**
* @Interface: ICharge
* @Description: 充电器接口
* @Author: Jerry(姜源)
* @Create: 20/09/12 12:53
*/
public interface ICharge {
void charge();
}

手机充电器类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import com.demo.designmode.adapter.isobject.ICharge;

/**
* @Class: AppleChargerIChargeImpl
* @Description: 苹果手机充电器需要适配的角色(Adapee)
* @Author: Jerry(姜源)
* @Create: 20/09/12 12:54
*/
public class AppleChargerIChargeImpl implements ICharge {
@Override
public void charge() {
System.out.println("苹果手机正在充电...");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import com.demo.designmode.adapter.isobject.ICharge;

/**
* @Class: AndroidChargerIChargeImpl
* @Description: 安卓手机充电器需要适配的角色(Adapee)
* @Author: Jerry(姜源)
* @Create: 20/09/12 13:21
*/
public class AndroidChargerIChargeImpl implements ICharge {
@Override
public void charge() {
System.out.println("安卓手机正在充电...");
}
}

适配器接口:

1
2
3
4
5
6
7
8
9
/**
* @Interface: IChargeAdapter
* @Description: 要对这个特殊的充电器进行适配, 适配器接口(Target角色)
* @Author: Jerry(姜源)
* @Create: 20/09/12 12:56
*/
public interface IChargeAdapter {
void charge();
}

对象的适配器类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @Class: UniversalCharger
* @Description: 万能充电器, 类的适配器(Adaper)
* @Author: Jerry(姜源)
* @Create: 20/09/12 13:22
*/
public class UniversalCharger implements IChargeAdapter {
private ICharge iCharge;

public UniversalCharger(ICharge iCharge) {
this.iCharge = iCharge;
}

@Override
public void charge() {
iCharge.charge();
}
}

启动类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import com.demo.designmode.adapter.isobject.impl.AndroidChargerIChargeImpl;
import com.demo.designmode.adapter.isobject.impl.AppleChargerIChargeImpl;

/**
* @Class: MainClass
* @Description: 启动类
* @Author: Jerry(姜源)
* @Create: 20/09/12 13:04
*/
public class StartClass {
public static void main(String[] args) {
UniversalCharger uc;
uc = new UniversalCharger(new AppleChargerIChargeImpl());
uc.charge();

uc = new UniversalCharger(new AndroidChargerIChargeImpl());
uc.charge();
}
}

image-20200912132555963

3. 应用场景

  • 类的适配器模式
    当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
  • 对象的适配器模式
    当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个包装类,持有原类的一个实例,在包装类的方法中,调用实例的方法就行。

07-适配器模式
https://janycode.github.io/2020/09/12/10_设计模式/07-适配器模式/
作者
Jerry(姜源)
发布于
2020年9月12日
许可协议