一、定义
适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
例如我们在给手机充电时,连接到插座上的那个,它的学名就称之为”适配器”。例如我们国家提供的是220v的电,我们手机充电需要的却只需要5v,所以我们的手机插头就是一个适配器,将22v的电转换适合5v的手机使用。
二、角色
目标角色(target):这是客户锁期待的接口。目标可以是具体的或抽象的类,也可以是接口
适配者角色(adaptee):已有接口,但是和客户器期待的接口不兼容,需要适配的类或适配者类
适配器角色(adapter):通过包装一个需要适配的对象,将已有接口转换成目标接口。
三、适用场景
1,系统需要使用现有的类,但现有的类却不兼容。
2,需要建立一个可以重复使用的类,用于一些彼此关系不大的类,并易于扩展,以便于面对将来会出现的类。
3,需要一个统一的输出接口,但是输入类型却不可预知。
注意设计之初,最好不要这种设计模式,适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。
四、分类
-
1、类适配器模式(class adapter pattern)
-
2、对象适配器模式(object adapter pattern)
-
3、缺省适配器模式(default adapter pattern),也叫默认适配器模式、接口适配器模式
注意:
类适配器使用继承关系复用适配源(Adaptee),因此目标(Target)不能是类,只能是接口(java单继承)。
对象适配器使用委派关系复用适配源(Adaptee),因此目标(Target)可能是类或接口,可以将多个适配源适配到一个目标接口。
五、代码案例问题引入
以手机充电器适配器为例,目前市面上大多数适配器都是将220V电压进行适配为5V电压供手机使用,我们就以这个为例编写代码看看。
六、类适配器
1、结构
//目标接口,或称为标准接口
public interface Target {
//普通功能
public void request();
}
//已存在的、具有特殊功能、但不符合我们既有的标准接口的类
public class Adaptee {
public void specificRequest() {
}
}
//适配器类,继承了被适配类,同时实现标准接口
public class Adapter extends Adaptee implements Target {
@Override
public void request() {
this.specificRequest();
}
}
2、代码案例
适配者角色
package adapter;
/**
* @Package: adapter
* @ClassName: UPower 需要适配的类(Adaptee):需要适配的类或适配者类
* @Author: tanp
* @Description: 国家供电220V
* @Date: 2020/11/3 10:54
*/
public class UPower {
/**
* @Description 提供220V电
* @Date 2020/11/3 10:57
* @Author tanp
*/
public int outPower(){
return 220;
}
}
目标角色
package adapter;
/**
* @Package: adapter
* @ClassName: MyNeedPower 目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口
* @Author: tanp
* @Description: 家电需要的电量接口 类适配器使用继承关系复用适配源(Adaptee),因此目标(Target)不能是类,只能是接口(java单继承)。
* @Date: 2020/11/3 10:57
*/
public interface MyNeedPower {
public int neddPower();
}
适配器角色
package adapter;
/**
* @Package: adapter
* @ClassName: MyAdapte 适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口
* @Author: tanp
* @Description: 电源适配器
* @Date: 2020/11/3 11:00
*/
public class MyAdapte extends UPower implements MyNeedPower{
@Override
public int neddPower() {
//获取需要适配的类的电量
int srcPoewr = outPower();
//自己做逻辑处理,返回家电需要的电量接口所需的电量
return srcPoewr/44;
}
}
main
package adapter;
/**
* @Package: adapter
* @ClassName: DemoClient
* @Author: tanp
* @Description: ${description}
* @Date: 2020/11/3 11:02
*/
public class DemoClient {
public static void main(String[] args) {
MyNeedPower myNeedPower = new MyAdapte();
int power = myNeedPower.neddPower();
System.out.println("经过适配器后,输出我需要的电量为"+power);
}
}
结果截图
3、优点
由于适配器adapter类是适配者adaptee类的子类,因此可以在适配器类中置换一些适配者的方法,即Override(重写),使得适配器的灵活性更强。
七、对象适配器
1、结构
//目标接口,或称为标准接口
public interface Target {
//普通功能
public void request();
}
//已存在的、具有特殊功能、但不符合我们既有的标准接口的类
public class Adaptee {
public void specificRequest() {
}
}
//适配器类,直接关联被适配类,同时实现标准接口
class Adapter implements Target {
// 直接关联被适配类
private Adaptee adaptee;
// 可以通过构造函数传入具体需要适配的被适配类对象
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
public void request() {
// 这里是使用委托的方式完成特殊功能
this.adaptee.specificRequest();
}
}
2、代码案例
适配者角色
package adapter.v1;
/**
* @Package: adapter.v1
* @ClassName: UPower 需要适配的类(Adaptee):需要适配的类或适配者类
* @Author: tanp
* @Description: 国家供电220V
* @Date: 2020/11/3 11:13
*/
public class Upower {
/**
* @Description 提供220V电
* @Date 2020/11/3 10:57
* @Author tanp
*/
public int outPower(){
return 220;
}
}
目标角色
package adapter.v1;
/**
* @Package: adapter.v1
* @ClassName: MyNeedPower 目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口
* @Author: tanp
* @Description: 家电需要的电量接口 对象适配器使用委派关系复用适配源(Adaptee),因此目标(Target)可能是类或接口,可以将多个适配源适配到一个目标接口。
* @Date: 2020/11/3 10:57
*/
public interface MyNeedPower {
public int neddPower();
}
适配器
package adapter.v1;
/**
* @Package: adapter.v1
* @ClassName: MyAdapte
* @Author: tanp
* @Description: ${description}
* @Date: 2020/11/3 11:16
*/
public class MyAdapte implements MyNeedPower{
Upower upower;
public MyAdapte(Upower upower){
this.upower = upower;
}
@Override
public int neddPower() {
//获取需要适配的类的电量
int srcPower = upower.outPower();
//自己做逻辑处理,返回家电需要的电量接口所需的电量
return srcPower/44;
}
}
main
package adapter.v1;
/**
* @Package: adapter.v1
* @ClassName: DemoClient
* @Author: tanp
* @Description: ${description}
* @Date: 2020/11/3 11:02
*/
public class DemoClient {
public static void main(String[] args) {
MyNeedPower myNeedPower = new MyAdapte(new Upower());
int power = myNeedPower.neddPower();
System.out.println("经过适配器后,输出我需要的电量为"+power);
}
}
打印结果
3、优点
一个对象适配器可以把多个不同的适配者adaptee适配到一个目标,也就是说,同一个适配器可以将适配者类和它的子类都适配到目标接口。
4、缺点
不能置换适配者类的方法。如果想修改适配者类的一个或多个方法,就只好先创建一个继承与适配者类的子类,把适配者类的方法置换掉,然后把适配者的子类当做真正的适配者进行适配,实现过程较为复杂。
八、总结
八、总结
适配器模式不并是那种会让架构变得更合理的模式,更多的时候它只是充当救火队员的角色,帮助解决由于前期架构设计不合理导致的接口不匹配的问题。