定义
将一个类的接口转换成客户希望的另外一个接口,适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
有类适配器,对象适配器,接口适配器。
1.类适配器原理:通过继承新类和实现原本的接口来实现。extends 新类 implements 原本的接口
结构图:
由图可知适配器模式包含一下三个角色:
- Target(目标抽象类):目标抽象类定义客户所需的接口,可以是一个抽象类或者接口,也可以是具体类。
- Adapter(适配器类):它可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配。它是适配器模式的核心。
- Adaptee(适配者类):适配者即被适配的角色,他定义了一个已经存在的接口,这个接口需要适配,适配者类封装好了客户希望的业务方法。
有一个播放电影的接口类PlayMovie,现在只能播放avi格式的电影,我们用适配器模式,使它能够播放MP4格式的电影。
package com.zlfan.classadapter;
public interface PlayMovie {
//假设这个已存在的接口只能播放avi格式
void playMovie();
}
package com.zlfan.classadapter;
/*
* 播放MP4的新类
*/
public class PlayMP4Adaptee {
void playMP4Movie(){
System.out.println("MP4格式播放电影");
}
}
package com.zlfan.classadapter;
/*
* 适配器类
*/
public class Adapter extends PlayMP4Adaptee implements PlayMovie{
@Override
public void playMovie() {
super.playMP4Movie();
}
}
package com.zlfan.classadapter;
/*
* 客户类:使用了客户希望的业务方法
*/
public class Client {
public static void main(String[] args) {
PlayMovie fm = new Adapter();
fm.playMovie();
}
}
运行结果:
MP4格式播放电影
这就是类适配器。调用还是以前的调用方式,但是其真正的实现方法是调用了新类的方法。super.playMP4Movie();
2.对象适配器:
其实与上面没有什么不同,只是把新类对象作为了适配器Adapter的字段来使用。
只需要更改适配器类即可,代码如下:
package com.zlfan.objectadapter;
/*
* 适配器类:把新类对象作为自己的字段
*/
public class Adapter implements PlayMovie{
private PlayMP4Adaptee mp4 = new PlayMP4Adaptee();
@Override
public void playMovie() {
mp4.playMP4Movie();
}
}
同样是能播放MP4的,推荐使用对象适配器。
值得注意的是:适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。
3.接口适配器
原理:通过抽象类来实现适配,这种适配稍别于上面所述的适配。
当存在这样一个接口,其中定义了N多的方法,而我们现在却只想使用其中的一个到几个方法,如果我们直接实现接口,那么我们要对所有的方法进行实现,哪怕我们仅仅是对不需要的方法进行置空(只写一对大括号,不做具体方法实现)也会导致这个类变得臃肿,调用也不方便,这时我们可以使用一个抽象类作为中间件,即适配器,用这个抽象类实现接口,而在抽象类中所有的方法都进行置空,那么我们在创建抽象类的继承类,而且重写我们需要使用的那几个方法即可。
目标接口:A
public interface A {
void a();
void b();
void c();
void d();
void e();
void f();
}
适配器:Adapter
public abstract class Adapter implements A {
public void a(){}
public void b(){}
public void c(){}
public void d(){}
public void e(){}
public void f(){}
}
实现类:B
public class B extends Adapter {
public void a(){
System.out.println("实现A方法被调用");
}
public void d(){
System.out.println("实现d方法被调用");
}
}
测试类:Client
public class Client {
public static void main(String[] args) {
A a = new B();
a.a();
a.d();
}
}
适配器模式运用场景
修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。
- 想使用一个已经存在的类,而它的接口不符合要求。
- 想创建一个可以用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
- (仅适用对象Adapter)想使用一个已存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它们的父接口。
优缺点
优点:可以让任何两个没有关联类一起运行。提高了类的复用。
缺点:过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。