适配器模式是一种结构型设计模式。
适配器模式的思想是:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
举例:
我有苹果的充电器,但是我是安卓的手机,我就需要一个充电转换器将苹果充电器转换为安卓充电器,诸恶个转换器即使适配器;
适配器模式涉及3个角色:
源(Adaptee):需要被适配的对象或类型。
适配器(Adapter):连接目标和源的中间对象,相当于插头转换器。
目标(Target):期待得到的目标,接口。
适配器模式包括3种形式:类适配器模式、对象适配器模式、接口适配器模式(或又称作缺省适配器模式)。
1、类适配器模式
原理:通过继承来实现适配器功能。
详见下方实例:我们以苹果充电器与安卓充电器的转接为例
接口:
/**
* Created by yd on 2019/4/16.
* 苹果充电器接口
*/
public interface Apple {
void apple();
}
/**
* Created by yd on 2019/4/16.
* 安卓充电器接口
*/
public interface Android {
void android();
}
实现类:
/**
* Created by yd on 2019/4/16.
* 安卓充电器实现类
*/
public class AndroidUser implements Android{
public void android(){
System.out.println("我是安卓充电器");
}
}
适配器:
/**
* Created by yd on 2019/4/16.
* 类适配器模式
* 原理:通过继承来实现适配器功能。
*/
public class Adapter extends AndroidUser implements Apple {
@Override
public void apple(){
android();
}
/**
* Created by yd on 2019/4/16.
* 适配器模式:将一个类的方法接口转换成客户希望的另外一个接口。
* 测试类
*/
public static void main(String[] args) {
Apple apple = new Adapter();
apple.apple();
}
}
运行结果:
我是安卓充电器
实例讲解:
我有一个Apple充电器,但是我是Android的手机,怎么办呢?弄个转换器,
将Apple充电器转换成为Android充电器就可以使用了。
接口Apple:描述苹果充电器接口格式
接口Android:描述安卓充电器接口格式
类AndroidUser:是接口Android的实现类,是具体的接口Android接口格式
Adapter:用于将Apple充电器接口格式转换成为Android充电器接口格式
2、对象适配器模式
原理:通过组合来实现适配器功能。
对象适配器模式是另外6种结构型设计模式的起源。
/**
* Created by yd on 2019/4/16.
* 类适配器模式
* 原理:通过继承来实现适配器功能。
*/
public class Adapter2 implements Apple {
private AndroidUser user;
public Adapter2(AndroidUser user){
this.user = user;
}
@Override
public void apple(){
user.android();
}
public static void main(String[] args) {
Apple apple2 = new Adapter2(new AndroidUser());
apple2.apple();
}
}
运行结果:
我是安卓充电器
类适配器与对象适配器的区别:
类适配器使用的是继承的方式,直接继承了AndroidUser,所以无法对AndroidUser的子类进行适配。
对象适配器使用的是组合的方式,所以AndroidUser及其子孙类都可以被适配。另外,对象适配器对于增加一些新行为非常方便,而且新增加的行为同时适用于所有的源。
基于组合/聚合优于继承的原则,使用对象适配器是更好的选择。但具体问题应该具体分析,某些情况可能使用类适配器会适合,最适合的才是最好的。
3、接口适配器模式
原理:通过抽象类来实现适配,这种适配稍别于上面所述的适配。
目标接口:
public interface A {
void a();
void b();
void c();
void d();
void e();
}
适配器:Adapter:
public abstract class Adapter3 implements A {
public void a(){};
public void b(){};
public void c(){};
public void d(){};
public void e(){};
}
实现类:Ashili
public class Ashili extends Adapter3{
public void a(){
System.out.println("实现A方法");
};
public void c(){
System.out.println("实现C方法");
};
public static void main(String[] args) {
A a = new Ashili();
a.a();
a.c();
}
}
运行结果:
实现A方法
实现C方法
4、适配器模式的优缺点
优点
更好的复用性:系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。
更好的扩展性:在实现适配器功能的时候,可以扩展自己源的行为(增加方法),从而自然地扩展系统的功能。
缺点
会导致系统紊乱:滥用适配器,会让系统变得非常零乱。例如,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
5、适配器模式应用场景
类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别,二者主要用于如下场景:
(1)想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。
(2)我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。
以上两个场景其实就是从两个角度来描述一类问题,那就是要访问的方法不在合适的接口里,一个从接口出发(被访问),一个从访问出发(主动访问)。
接口适配器使用场景:
(1)想要使用接口中的某个或某些方法,但是接口中有太多方法,我们要使用时必须实现接口并实现其中的所有方法,可以使用抽象类来实现接口,并不对方法进行实现(仅置空),然后我们再继承这个抽象类来通过重写想用的方法的方式来实现。这个抽象类就是适配器。