一、介绍

概念:一个类的接口转换成客户端希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。即根据已有的接口,生成想要的接口。

先看下面这个小例子体会一下适配器模式:

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
public class AppTest {
/**
*
* 符合开闭原则,源代码没有进行修改
* 也符合组合优于继承原则(只是进行复用)
*/
public static void main(String[] args) {
Calculate calculate = new Calculate(); // 原来的接口是接两个
CalcAdapter calcAdapter = new CalcAdapter(calculate); // 做个适配器,可以接收三个
int add = calcAdapter.add(1, 2, 3);
System.out.println(add);
}
}

// 基本计算器
class Calculate {
public int add(int a, int b) {
return a + b;
}
}

// 变化来了,客户想要计算三个数的和 - 采用适配器模式的方式,将接口转换成我们需要的形式
class CalcAdapter {
private Calculate calculate; // 复用其功能,采用组合的方式。组合需要被是适配的类

public CalcAdapter(Calculate calculate) {
this.calculate = calculate;
}

public int add(int a, int b, int c) {
return calculate.add(a, calculate.add(b, c)); // 做到对功能的复用
}
}

二、实例

该章节中对适配器模式的讲解,采用Java编程思想的实例,进行介绍。

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
51
52
53
class Processor {
public String name() {
return getClass().getSimpleName();
}

Object process(Object input) {
return input;
}
}

class Upcase extends Processor {
@Override
String process(Object input) { // 重写中,返回值可以进行向上转型
return ((String) input).toUpperCase();
}
}

class DownCase extends Processor {
@Override
String process(Object input) { // 重写中,返回值可以进行向上转型
return ((String) input).toLowerCase();
}
}

class Splitter extends Processor {
@Override
String process(Object input) { // 重写中,返回值可以进行向上转型
return Arrays.toString(((String) input).split(" "));
}
}

class Apply {
public static void process(Processor p, Object s) {
System.out.println("Using Process: " + p.name());
System.out.println(p.process(s));
}
}

public class AppTest {
public static void main(String[] args) {
String s = "How are you";
Apply.process(new Upcase(), s);
Apply.process(new DownCase(), s);
Apply.process(new Splitter(), s);
}
}
=== 结果 ===
Using Process: Upcase
HOW ARE YOU
Using Process: DownCase
how are you
Using Process: Splitter
[How are you]

该段代码中,主要是为了复用Processor类中的process方法,对process的方法采用三种不同实现方式,即设计三个不同的子类。

现在又发现了一个跟process功能相似的类:

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
51
52
53
54
55
class Waveform {
private static long counter;
private final long id = counter++;

@Override
public String toString() {
return "waveform" + id;
}
}

class Filter {
public String name() {
return getClass().getSimpleName();
}

public Waveform process(Waveform input) {
return input;
}
}

class LowPass extends Filter {
double cutoff;

public LowPass(double cutoff) {
this.cutoff = cutoff;
}

public Waveform process(Waveform input) {
return input; // 对该input的 Dummy processing
}
}

class HighPass extends Filter {
double cutoff;

public HighPass(double cutoff) {
this.cutoff = cutoff;
}

public Waveform process(Waveform input) {
return input; // 对该input的 Dummy processing
}
}

class BandPass extends Filter {
double cutoff;

public BandPass(double cutoff) {
this.cutoff = cutoff;
}

public Waveform process(Waveform input) {
return input; // 对该input的 Dummy processing
}
}

从这段代码中,我们可以看到Filter和前面我们自己定义的Processor类似,同样的有三个子类也同Processor的子类。

此时,我们如果想要复用Apply的方法,参数却无法传入。因为,Apply参数接收的是Processor类及其子类。这个时候,你肯定想,那就直接将Filter继承Processor类,让其成为子类不就好了?但是,不要忘记,Filter代码是别人的代码,我们无法对其进行修改。同时,即使进行了修改,那也违反了开闭原则

所以我们需要用接口的方式,让Apply接收的是接口:

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
interface Processor {
String name();

Object process(Object input);
}

abstract class AbstractProcess implements Processor {
@Override
public String name() {
return getClass().getSimpleName();
}
}

class Upcase extends AbstractProcess {
@Override
public String process(Object input) { // 重写中,返回值可以进行向上转型

return ((String) input).toUpperCase();
}
}

class DownCase extends AbstractProcess {
@Override
public String process(Object input) { // 重写中,返回值可以进行向上转型
return ((String) input).toLowerCase();
}
}

class Splitter extends AbstractProcess {
@Override
public String process(Object input) { // 重写中,返回值可以进行向上转型
return Arrays.toString(((String) input).split(" "));
}
}

在上面中,我们将Process设计成了接口,并且使用了一个AbstractProcess抽象类,实现这个接口,再用子类去继承这个抽象类。设计这个抽象类的原因是,子类如果直接实现Process接口,那么name()这个方法都是重复实现,所以直接使用抽象类进行该方法的实现,即对一些固定功能进行实现,再设计子类直接继承这个抽象类对process方法进行自己所需要的实现。所以也能看见,抽象类是对接口中固定功能的实现进行抽取,即定义出一些模板方法,这样子类就不需要进行重复实现了。

现在继续看Apply类:

1
2
3
4
5
6
class Apply {
public static void process(Processor p, Object s) {
System.out.println("Using Process: " + p.name());
System.out.println(p.process(s));
}
}

此时接收的参数Process是接口,表明只要是实现了该接口的类及其实现类的子类都能被传入。那么我们该如何传入这个参数呢?即采用适配器模式。设计一个适配器去实现该接口,将被适配的类和适配器进行关联,而适配器作为接口的具体的实现,这样适配器就能够被作为参数进行传入,而具体使用的是被适配类的方法。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class FilterAdapter implements Processor {

private Filter filter; // 和被适配的对象产生关联关系

public FilterAdapter(Filter filter) {
this.filter = filter;
}

@Override
public String name() {
return filter.name();

}

@Override
public Object process(Object input) {
Waveform process = filter.process((Waveform) input); // 真正调用的process方法,还是所发现的类中的process方法;目的是让发现的类的process能够适配我们自己的process接口,目的是让接口复用;而不用再写一个接口
return process;
}
}

此时我们就可以直接复用process代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class AppTest {
public static void main(String[] args) {
String s = "How are you";
// 当调用process方法时,传入的是适配器,调用适配的process方法,最终是调用的Filter的process方法,而调用p.name(),最终也是调用的filter的filter.name()方法,这样就能让我们所要适配的类去使用之前已经实现的代码了
Apply.process(new FilterAdapter(new LowPass(1)), new Waveform());
Apply.process(new FilterAdapter(new HighPass(1)), new Waveform());
Apply.process(new FilterAdapter(new BandPass(1)), new Waveform());
}
}
===结果===
Using Process: LowPass
waveform: [0]
Using Process: HighPass
waveform: [1]
Using Process: BandPass
waveform: [2]

适配器实现接口而没有继承类的原因是,如果使用继承,后面就不能再继承其它类了,而接口可以进行多实现,也可以看出接口比继承有着更宽松的规则(不仅可以是接口的实现类,其实现类的子类也能够作为参数进行传递)。

如果,我们不使用适配器,而是直接使用这个类会发生什么?

1
2
3
4
5
6
7
8
9
10
11
12
public class AppTest {
public static void main(String[] args) {
Filter lowPass = new LowPass(1);
System.out.println(lowPass.name());
System.out.println(lowPass.process(new Waveform()));
Filter highPass = new HighPass(1);
System.out.println(highPass.name());
System.out.println(highPass.process(new Waveform()));
Filter bandPass= new BandPass(1);
System.out.println(bandPass.name());
System.out.println(bandPass.process(new Waveform()));
}

无法使用Apply类提供的方法,明明所实现的都是一样的,可还需要多写一套代码,使用适配器,将需要被使用类的接口,转换成能够被适配的接口。

三、使用步骤

自定义适配器类,适配器继承被适配的接口,自定义的适配器类中组合被适配的类,在实现的方法中调用被适配类的方法。


Comment