设计模式详解之适配器模式
适配器模式是三大类型模式里面的结构类模式,它的定义主要是将一个类的接口变换成客户
端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
比如我们已经生产了接口A和接口B(如下图),而且产品已经上线了。但是这个时候我们需要让A接口和B接口对接,这就比较为难了,总不能推翻重新设计吧?
所有也就有了我们的适配器模式,我们的可以定义一个接口来同时适配A接口和B接口,来达到AB之间的对接。我们实现C接口如下:
上面的例子有点抽象,我们再举一个更具体一点的例子。在我们的生活中,有些电脑无法插网线,但是难道就不能有线上网了吗?不是的,我们就有了下面这一个网线转换器,来将原本不匹配的网线接口适配成了我们适合的USB接口,从而实现了有线上网。
下面我们用代码来具体实现一下这个网线适配器的工作流程。
类适配器实现例子
首先实现我们的Adaptee类
package adapter.demo01;
//我们需要被适配的接口,网线
public class Adaptee {
public void request(){
System.out.println("连接网线上网!");
}
}
我们可以抽象一个适配器的接口,然后再实现。方便管理
package adapter.demo01;
//接口转换器的抽象实现
public interface NetToUsb {
//作用;处理请求,网线接口->USB
public void handleRequest();
}
然后去实现我们的适配器,Adapter类
package adapter.demo01;
//我们的适配器,连接usb,还要连接网线
public class Adapter extends Adaptee implements NetToUsb {
@Override
public void handleRequest() {
super.request(); //实现上网的功能,提供给电脑调用
}
}
最后就是我们的电脑类Computer,就可以使用上网功能了
package adapter.demo01;
public class Computer {
//电脑上网的功能
public void getNet (NetToUsb adapter){
adapter.handleRequest();
}
public static void main(String[] args) {
//实例化我们的电脑,适配器,网线
Computer computer = new Computer();
Adapter adapter = new Adapter();
Adaptee adaptee = new Adaptee();
//通过适配器连接网络
computer.getNet(adapter);
}
}
|----------------测试输出结果-------------------|
连接网线上网!
我们虽然实现了适配器模式,但是我们的适配器在适配被适配的接口的时候是通过继承来实现他的功能,要知道我们的Java是不支持多继承的,那是不是就意味着我们的适配器只能适配一个接口?也就是我们的适配器只能适配网线的头吗?但是我们的生活中可是存在可以同时适配多个头的转换器呢,所有有了我们的对象适配器。
对象适配器例子
还是上面那个例子,我们的适配器进行修改,不再是通过继承来实现网线上网的功能,而是组合来实现。
package adapter.demo01;
//我们的适配器,连接usb,还要连接网线
public class Adapter implements NetToUsb {
//定义我们需要适配的头
private Adaptee adaptee;
//在构造器的里面实例对象
public Adapter(Adaptee adaptee){
this.adaptee = adaptee;
}
@Override
public void handleRequest() {
adaptee.request(); //实现上网的功能,提供给电脑调用
}
}
然后在我们的电脑使用的时候,需要给适配器传入我们需要适配和接口,然后电脑连接适配器就行了。
package adapter.demo01;
public class Computer {
//电脑上网的功能
public void getNet (NetToUsb adapter){
adapter.handleRequest();
}
public static void main(String[] args) {
//实例化我们的电脑,网线,适配器
Computer computer = new Computer();
Adaptee adaptee = new Adaptee();
Adapter adapter = new Adapter(adaptee);
//通过适配器连接网络
computer.getNet(adapter);
}
}
|----------------测试输出结果-------------------|
连接网线上网!
总结
可能还会有小伙伴可能会有和我刚开始的疑惑,就上面那个例子,为什么电脑在代码那里修改一下,就可以调用网线类了,为什么还需要适配器呢?我们上面的例子是为了能说明适配器的作用,具体的工程的话,适配器模式最好在详细设计阶段不要考虑它,它不是为了解决还处在开发阶段的问题,而是解决正在服役的项目问题,没有一个系统分析师会在做详细设计的时候考虑使用适配器模式。就像我们的电脑,我们在造电脑的时候谁知道要去实现一个网线这样的接口,但是后面我们不得不要使用,那只能补救了,用适配器来弥补了。
总结一下,关于适配器我们介绍了类适配器和对象适配器。具体使用肯定是推荐使用对象适配器。
对象适配器的优点:
- 一个对象适配器可以把多个不同的适配者适配到同一个目标(也就是我上面提到的,一个转换器有多个头)
- 可以适配一个适配者的子类,由于适配器和适配者之间是关联关于,根据“里氏替换原则”,适配者的子类也可以通过该适配器进行适配。
类适配器的缺点:
- 在不能实现多继承的编程语言中,与对象适配器相反,一次最多只能适配一个适配者类,不能同时适配多个适配者
- 在大部分的编程语言中,类适配器模式中的目标抽象类只能为接口,不能为类,其使用有一定的局限性。
适配器模式的优点:
- 增加了类的透明性,比如我们使用电脑的上网功能,但是具体联网都委托在了网线那边,这对我们的高层次模块是透明,也是不需要关心的。
- 提高了类的复用度,我们的网线可以给原本就有该网线接口的电脑使用,现在也可以给只有USB接口的电脑使用,避免了去再创建专属于USB接口的网线了。
- 灵活性非常好,如果不想要适配器,直接删掉就行,代码都不用修改。
应用场景:
- 需要使用一个已有或新建立的类,但这个类又不符合系统的接口(如方法名)
- 想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作
参考资料
设计模式之禅(第二版)