设计模式之适配器模式
适配器模式
模式定义
- 官方定义:将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
- 个人理解:上面说的比较官方,说白了就是比如有两个接口 A 和 B ,现在客户端在调用的时候想通过A 来调用到B的功能, 这样显然是不可以的,所以我们就需要一个中间类,来将两个类进行关联,通过这个适配器类让这两个接口强行产生关系。说到这可能有人会想为什么在设计之初不将A和B接口进行关联,反而要这么麻烦的通过适配器类来将它们进行关联呢? 这就会抛出对适配器模式使用时机的知识点,适配器模式使用时机是当前已有系统在升级改造时或者系统需要和第三方进行对接的情况下。而不是在系统设计之初就使用它,这样显然是很不合理的。
优缺点
-
优点
-
通过适配器类来将两个不相关的接口关联,这样就不用修改原接口,保留了可拓展性。
-
适配器类在将两个接口进行关联的时候,所做的修改对客户端是透明,同时也不会影响到原来的接口结构。
-
-
缺点
- 如果有多个接口都需要的适配的话,那么适配器类的数量会大大增加,因为java只有单继承机制,所以每个适配器类只能为一个接口进行适配(可以通过对象适配器方法解决)。
- 过多的使用适配器会增加系统的理解难度,比如 客户端明明调用的A接口的run方法但是底层却被适配器适配到了B 接口的fly方法。
举个栗子
比如我现在有一个耳机但是耳机的插头是圆孔的,但是我的电脑是只有USB 没有圆孔插头的现在就需要一个适配器来进行适配,将耳机和电脑连接起来,一遍插入耳机的圆孔,然后将适配器的另一端插入电脑的USB口。
可以看到适配器模式基本角色为三个
- 适配器:适配器作为一个中间类,可以为被适配者和目标接口进行适配,是适配器模式的核心部分。
- 被适配者:要被执行的真正方法即提供的能力,在本例子中为耳机的播放声音方法。
- 目标接口:被适配的最终接口,即客户端使用的调用方,在本例子中体现为电脑的USB接口。
下面看具体代码
package cn.hsh.study.adapter;
/**
* @author shaohua
* @date 2021/4/13 21:12
*/
public interface Computer {
void outVoice();
}
package cn.hsh.study.adaptee;
/**
* @author shaohua
* @date 2021/4/13 21:10
*/
public class Headset {
public void outVoice(){
System.out.println("耳机发出声音");
}
}
package cn.hsh.study.adapter;
import cn.hsh.study.adaptee.Headset;
/**
* @author shaohua
* @date 2021/4/13 21:14
*/
public class Adapter implements Computer {
private Headset headset;
public Adapter(Headset headset){
this.headset = headset;
}
public void outVoice() {
this.headset.outVoice();
}
}
package cn.hsh.study;
import cn.hsh.study.adaptee.Headset;
import cn.hsh.study.adapter.Adapter;
import cn.hsh.study.adapter.Computer;
/**
* @author shaohua
* @date 2021/4/13 21:12
*/
public class Client {
public static void main(String[] args) {
Computer computer = new Adapter(new Headset());
computer.outVoice();
}
}
运行结果:
对象适配器模式
对象适配器模式是适配器的另一种实现,相较于类适配器的优点是将适配器类和被适配者类进行分离,用关联关系取代静态继承关系。这样的话一个适配器类就可以为多个被适配者类的类进行适配。
下面看代码实现
- 首先还是老样子,定义一个目标接口
package cn.hsh.study.object.adapter;
/**
* @author shaohua
* @date 2021/4/15 20:42
*/
public interface Computer {
void out();
}
- 定义被适配者类(可以是普通类,抽象类,接口)
package cn.hsh.study.object.adapter;
/**
* @author shaohua
* @date 2021/4/15 20:42
*/
public class Headset {
public void out(){
System.out.println("对象适配器发出声音");
}
}
- 为适配者类定义子类实现(华为耳机)
package cn.hsh.study.object.adapter;
/**
* @author shaohua
* @date 2021/4/15 20:45
*/
public class HUAWEIHeadset extends Headset {
@Override
public void out() {
System.out.println("华为耳机发出声音");
}
}
- 为被适配者类定义第二个子类实现(罗技耳机)
package cn.hsh.study.object.adapter;
/**
* @author shaohua
* @date 2021/4/15 20:43
*/
public class Logic extends Headset {
@Override
public void out() {
System.out.println("罗技耳机发出声音");
}
}
- 然后到了最关键的步骤,我们来定义适配器。这里我们可以看到,我们将类适配器的继承模式改为了关联模式。
package cn.hsh.study.object.adapter;
/**
* @author shaohua
* @date 2021/4/15 20:41
*/
public class Adapter implements Computer {
private Headset headset;
public Adapter(Headset headset){
this.headset = headset;
}
public void out() {
this.headset.out();
}
}
- 最后客户端调用
package cn.hsh.study.object.adapter;
/**
* @author shaohua
* @date 2021/4/15 20:41
*/
public class Client {
public static void main(String[] args) {
Computer computer = new Adapter(new HUAWEIHeadset());
computer.out();
computer = new Adapter(new Logic());
computer.out();
}
}
我们来看客户端调用, 这个时候我们就实现了一个适配器类适配多个被适配者类的方式,我们可以为多个类型的耳机进行适配。
执行结果
总结
适配器模式不应该在系统的设计之初使用,而是在系统升级维护,或者对接第三方系统导致双方接口不兼容的时候才使用,使用的时候是用类适配器还是对象适配器根据具体情况而定,各有优缺点。