适配器模式

Catalogue   

定义

适配器模式(Adapter Pattern):将一个类的接口转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以相互合作。
适配器模式有类的适配器模式对象的适配器模式两种不同的形式。

适配器模式优点

  • 复用且不修改类 : 不改变现有类的基础上 , 提高类的复用性 , 透明性 ; 让现有类与目标类接口匹配 ;
  • 降低耦合 : 目标类 ( 用户调用的接口所在类 ) 和 现有类 ( 被适配者 ) 解除耦合 , 降低了系统的耦合性 , 易于扩展维护;
  • 符合开闭原则 : 用户调用适配器接口 , 只与适配器类进行交互 , 如果需要修改扩展 , 只需要修改适配器类即可 , 目标类和现有类各自都是相互独
    立的 , 互不影响 ;

适配器模式缺点

  • 增加复杂性 : 编写适配器类时 , 需要考虑全面 , 包括被适配者 和 目标类 , 系统复杂性会增加;
  • 降低可读性 : 系统代码可读性降低 , 可维护性降低 ;

对象适配器

在对象适配器模式中,适配器与适配者之间是关联关系(适配者是适配器的成员变量)。

结构图

  • Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。
  • Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,
    它通过继承(或者实现)Target并关联一个Adaptee对象使二者产生联系。
  • Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的
    业务方法,在某些情况下可能没有适配者类的源代码。
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
package com.shjlone.designpattern.adapter.objectadapter;

/**
* 对象适配器模式
*/
public class ObjectAdapterTest {
public static void main(String[] args) {
TypeC typeC = new Phone();
MicroUsb microUsb = new Adapter(typeC);
microUsb.microUsb();
}
}

// 供应接口
interface MicroUsb {
public void microUsb();
}

// 需求接口
interface TypeC {
public void typeC();
}

// 需求实现类
class Phone implements TypeC {
public void typeC() {
System.out.println("Type-C接口");
}
}

// 适配器
class Adapter implements MicroUsb {
private TypeC typeC;

public Adapter(TypeC typeC) {
this.typeC = typeC;
}

@Override
public void microUsb() {
typeC.typeC();
}
}

类适配器

在类适配器模式中,适配器与适配者之间是继承关系

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
package com.shjlone.designpattern.adapter.classadapter;

/**
* 类适配器
*/
public class ClassAdapterTest {

public static void main(String[] args) {
MicroUsb microUsb = new Adapter();
microUsb.microUsb();
}
}

//供应接口
interface MicroUsb {
public void microUsb();
}

//需求接口
interface TypeC {
public void typeC();
}

//需求实现类
class Phone implements TypeC {
public void typeC() {
System.out.println("Type-C接口");
}
}

//适配器
class Adapter extends Phone implements MicroUsb {
public void microUsb() {
typeC();
}
}

缺省适配器模式(Default Adapter Pattern)

当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),
那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的所有方法的情况,又称为单接口适配器模式。

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
48
49
50
package com.shjlone.designpattern.adapter.defaultadapter;

/**
* 默认适配器,用于隐藏一些实现细节
*/
public class DefaultAdapterTest {
public static void main(String[] args) {
TypecToVGA typecToVGA = new TypecToVGA();
typecToVGA.isTypeC();
typecToVGA.isVGA();
}
}

// 接口类
interface AllPorts {
public void isTypeC();

public void isVGA();

public void isHdmi();
}

// 适配器的框架
abstract class Adapter implements AllPorts {
@Override
public void isTypeC() {
}

@Override
public void isVGA() {
}

@Override
public void isHdmi() {
}
}

// 适配器类
class TypecToVGA extends Adapter {
@Override
public void isTypeC() {
System.out.println("信号从TypeC接口进入");
}

@Override
public void isVGA() {
System.out.println("信号从VGA接口出");
}
}

使用场景

  • Java连接数据的JDBC工具
  • List Arrays.asList(T[])
  • InputStreamReader
  • StringReader
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
/**
* 对象适配器
* StringReader相当于Adapter,Reader相当于Target,String相当于Adaptee
*
*
*/
public class StringReader extends Reader {

// 维持对adaptee对象的引用
private String str;

private int length;
private int next = 0;
private int mark = 0;

/**
* 构造注入一个String用于之后的read操作
*/
public StringReader(String s) {
this.str = s;
this.length = s.length();
}

// 这里相当于是在做适配操作,转为目标对象所期望的请求
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
if (next >= length)
return -1;
return str.charAt(next++);
}
}
}

参考