简介
Convert the interface of a class into another interface clients expect.Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
适配器模式(Adapter Pattern) 又叫做 变压器模式,它的功能是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而导致无法在一起工作的两个类能够一起工作。
也就是说,当前系统存在两种接口 A 和 B,客户只支持访问 A 接口,但是当前系统没有 A 接口对象,但是有 B 接口对象,但客户无法识别 B 接口,因此需要通过一个适配器 C,将 B 接口内容转换成 A 接口,从而使得客户能够从 A 接口获取得到 B 接口内容。
在软件开发中,基本上任何问题都可以通过增加一个中间层进行解决。适配器模式 其实就是一个中间层。
综上,适配器模式 其实起着 转化/委托 的作用,将一种接口转化为另一种符合需求的接口。就比如电源适配器,可以将家用220V交流电压转化为笔记本电脑充电的12V直流电压。
主要解决
提供一个转换器(适配器),将当前系统存在的一个对象转化为客户端能够访问的接口对象。
优缺点
优点:
- 具备 转化/委托 作用,可以让系统中两个没有任何关联的类在一起运行;
- 适配器模式 封装了底层 转换 细节,增加了类的透明度,客户端(高层模块)协议无需改变(只关注结果);
- 适配器模式 可以很好地支持系统扩展功能的实现。
缺点:
- 由于底层封装了其他接口转换细节,因此过多使用会导致系统凌乱,追溯困难;
使用场景
- 系统扩展时,存在一个需求类,但却不符合现有接口规范时,可以通过创建一个适配器进行适配;
- 当某个接口定义了大量方法,而我们却只需要实现其中一两个时,可以使用适配器(通常为一个抽象类) 空实现 该接口,然后我们继承该适配器,实现所需的那一两个方法即可;
模式讲解
适配器模式 一般包含三种角色:
- 目标角色(Target):也就是我们期望的接口;
- 源角色(Adaptee):存在于系统中,内容满足客户需求(需转换),但接口不匹配的接口实例;
- 适配器(Adapter):将源角色(Adaptee)转化为目标角色(Target)的类实例;
适配器模式 各角色之间的关系如下:
假设当前系统中,客户端需要访问的是 Target 接口,但 Target 接口没有一个实例符合需求,而 Adaptee 实例符合需求;但是客户端无法直接使用 Adaptee(接口不兼容);因此,我们需要一个适配器(Adapter)来进行中转,让 Adaptee 能转化为 Target 接口形式;
适配器模式 有3种形式:
- 类适配器
- 对象适配器
- 接口适配器
下面我们以一个示例进行讲解,来看下该示例分别用 类适配器,对象适配器 和 接口适配器 是怎样进行代码实现。例子如下:
假设我们要制作一个笔记本电源适配器(Adapter),能够将家用 220V 交流电(Adaptee)转成直流12V(Target)。
类适配器
原理:通过继承来实现适配器功能。
具体做法:让 Adapter 实现 Target 接口,并且继承 Adaptee,这样 Adapter 就具备 Target 和 Adaptee 的特性,就可以将两者进行转化;
类适配器下面我们看下 类适配器 的源码实现:
class Client {
public static void main(String[] args) {
//Adapter对象
Adapter adapter = new Adapter();
//进行转化
int result = adapter.output12();
System.out.println("输出电压: "+result);
}
// Target
interface IDC12 {
int output12();
}
// Adaptee角色,需要被转换的对象
static class AC220 {
int output220() {
return 220;
}
}
//Adapter
static class Adapter extends AC220 implements IDC12 {
@Override
public int output12() {
return super.output220() / 18;
}
}
}
对象适配器
原理:通过组合来实现适配器功能。
具体做法:让 Adapter 实现 Target 接口,然后内部持有 Adaptee 实例,然后再 Target 接口规定的方法内转换 Adaptee 。
对象适配器对象适配器 代码只需更改适配器(Adapter)实现,其他与 类适配器 一致:
static class Adapter implements IDC12 {
private AC220 ac220 = new AC220();
@Override
public int output12() {
return this.ac220.output220() / 18;
}
}
接口适配器
接口适配器 的关注点与 类适配器 和 对象适配器 的关注点不太一样, 类适配器 和 对象适配器 着重于将系统存在的一个角色(Adaptee)转化成目标接口(Target)所需内容,而 接口适配器 的使用场景是解决接口方法过多,如果直接实现接口,那么类会多出许多空实现的方法,类显得很臃肿。此时,使用 接口适配器 就能让我们只实现我们需要的接口方法,目标更清晰。
原理:抽象类实现接口,并 空实现 接口众多方法。
接口适配器下面我们看下 接口适配器 的源码实现:
class Client {
public static void main(String[] args) {
Adapter adapter = new Adapter(new AC220()) {
//只需实现一个方发即可
@Override
public int output12() {
return this.ac220.output220() / 18;
}
};
int result = adapter.output12();
System.out.println("输出电压: " + result);
}
// 接口拥有很多方法
interface IDC12 {
int output5();
int output12();
int output24();
int output36();
}
// Adaptee角色,需要被转换的对象
static class AC220 {
int output220() {
return 220;
}
}
// Adapter
static abstract class Adapter implements IDC12 {
AC220 ac220;
public Adapter(AC220 ac220) {
this.ac220 = ac220;
}
@Override
public int output12() {
return 0;
}
@Override
public int output5() {
return 0;
}
@Override
public int output24() {
return 0;
}
@Override
public int output36() {
return 0;
}
}
}
网友评论