定义:
适配器模式的定义是将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。就像一个变压器将高压电转换为低压电,因此适配器也称为变压器模式。下面是很形象的一个图:
![引用《设计模式之禅》](https://i-blog.csdnimg.cn/blog_migrate/2940e7921dd746445a10c4085d410568.png)
关键词:适配 转换
实现:
需求:现在有用户基本信息,用户家庭信息,用户办公信息三个接口,如何设计一个接口可以执行查询到用户的姓名,家庭住址和办公电话
设计思路:通过适配器的思想,用户基本信息、用户家庭信息和用户办公信息是现有的实现接口和实现类,也就是源角色但是还需要设计一个适配器接口和实现类来是三个信息类能在一起工作也就是适配器角色,并满足要求去调用,最终被调用的也就是目标角色。
代码实现:
/**
* 适配器模式
* 源角色
* 用户基本信息接口
*/
public interface IOuterUserBaseInfo {
//用户基本信息,比如:姓名,性别,手机号等
public Map getUserBaseInfo();
}
/**
* 适配器模式 源角色
* 用户基本信息类
*/
public class OuterUserBaseInfo implements IOuterUserBaseInfo{
/**
* 用户基本信息
*/
@Override
public Map getUserBaseInfo() {
HashMap baseMap = new HashMap();
baseMap.put("userName","员工姓名张三");
baseMap.put("mobileNumber","张三的电话是152****1122");
return baseMap;
}
}
/**
* 适配器模式 源角色
* 用户家庭信息接口
*/
public interface IOuterUserHomeInfo {
//用户家庭信息
public Map getUserHomeInfo();
}
/**
* 适配器模式 源角色
* 用户家庭信息类
*/
public class OuterUserHomeInfo implements IOuterUserHomeInfo{
/**
* 用户基本信息
*/
@Override
public Map getUserHomeInfo() {
HashMap homeMap = new HashMap();
homeMap.put("homeTelNumber","张三的家庭电话是010-33**1122");
homeMap.put("homeAddress","张三的家庭住址是深圳市");
return homeMap;
}
}
/**
* 适配器模式
* 用户工作信息接口 源角色
*/
public interface IOuterUserOfficeInfo {
//用户办公信息
public Map getUserOfficeInfo();
}
/**
* 适配器模式 源角色
* 用户办公信息类
*/
public class OuterUserOfficeInfo implements IOuterUserOfficeInfo{
/**
* 用户家庭信息
*/
@Override
public Map getUserOfficeInfo() {
HashMap officeMap = new HashMap();
officeMap.put("jobPosition","张三的职位是老板");
officeMap.put("officeTelNumber","员工的办公电话是****");
return officeMap;
}
}
/**
* 适配器模式 适配器角色
* 员工信息接口
*/
public interface IUserInfo {
//获取员工姓名
public String getUserName();
//获的家庭地址
public String getHomeAddress();
//获取手机号码
public String getMobileNumber();
//获取办公电话
public String getOfficeTelNumber();
//获取员工职位
public String getJobPosition();
//获取员工家庭电话
public String getHomeTelNumber();
}
/**
* 适配器模式 适配器角色和目前角色
* 适配器类
*/
public class OuterUserInfo implements IUserInfo{
//源目标对象
private IOuterUserBaseInfo userBaseInfo = null;//用户基本信息
private IOuterUserHomeInfo userHomeInfo = null;//用户家庭信息
private IOuterUserOfficeInfo userOfficeInfo = null;//用户办公信息
//数据处理
private Map baseMap = null;
private Map homeMap = null;
private Map officeMap = null;
//构造函数
public OuterUserInfo(IOuterUserBaseInfo userBaseInfo,IOuterUserHomeInfo userHomeInfo,IOuterUserOfficeInfo userOfficeInfo){
this.userBaseInfo = userBaseInfo;
this.userHomeInfo = userHomeInfo;
this.userOfficeInfo = userOfficeInfo;
baseMap = userBaseInfo.getUserBaseInfo();
homeMap = userHomeInfo.getUserHomeInfo();
officeMap = userOfficeInfo.getUserOfficeInfo();
}
@Override
public String getUserName() {
String userName = (String) baseMap.get("userName");
System.out.println(userName);
return userName;
}
@Override
public String getHomeAddress() {
String homeAddress = (String) baseMap.get("homeAddress");
System.out.println(homeAddress);
return homeAddress;
}
@Override
public String getMobileNumber() {
String mobileNumber = (String) baseMap.get("mobileNumber");
System.out.println(mobileNumber);
return mobileNumber;
}
@Override
public String getOfficeTelNumber() {
String officeTelNumber = (String) baseMap.get("officeTelNumber");
System.out.println(officeTelNumber);
return officeTelNumber;
}
/**
* 适配器模式客户端
*
*/
public class Client {
public static void main(String[] args) {
IOuterUserBaseInfo outerUserBaseInfo = new OuterUserBaseInfo();
IOuterUserHomeInfo userHomeInfo = new OuterUserHomeInfo();
IOuterUserOfficeInfo userOfficeInfo = new OuterUserOfficeInfo();
OuterUserInfo outerUserInfo = new OuterUserInfo(outerUserBaseInfo,userHomeInfo,userOfficeInfo);
//获取员工的姓名和办公电话和家庭住址
outerUserInfo.getUserName();
outerUserInfo.getOfficeTelNumber();
outerUserInfo.getHomeAddress();
}
}
//执行结果:
员工姓名张三
员工的办公电话是****
张三的家庭住址是深圳市
在上述代码中适配器角色和目标角色都为 OuterUserInfo ,适配器角色通过角色转换使得三个源角色共同被适用。
总结:
适配器的选型:适配器的模式根据实现的方式可以分为两种:对象适配器和类适配器。对象适配器是通过组合的形式,适用于源数据接口很多,也就是需要适配的接口很多,而且与适配器接口的形式有很大的不同,使用组合的模式能让适配器接口更加灵活。同样,当源数据接口同适配器接口契合度很高,那就可以采用类适配器,类适配器是通过继承的方式,减少代码量。上述选择都是基于源数据接口较多的情况,如果源数据接口不多,那其实选择哪种适配器就没那么重要了。
适配器的使用场景:对有缺陷的接口进行二次封装,比如调用外部接口的静态方法,不利于进行测试,此时就可以对接口通过适配器进行二次封装;统一多个类的入口,当调用多个行为类似的类时,为了使代码更简洁,可以通过适配器提供一个统一的接口入库;当调用方系统发生变化时,可以通过适配器模式,减少调用代码的改动;还有最常见的版本兼容问题,系统或接口升级,老版本的代码有时候应该调用依赖关系并不会立即下线,使用适配器来兼容老版本代码;兼容不同格式的数据处理。
适配器模式的优势:可以是两个不相关的类产生关联被工程使用,而且集中到目标角色中,这对调用者是透明的,适配器是如何进行适配的,调用者无需关心。同时是配置模式提高了类的复用性,并且不影响原有类的使用。
适配器的注意事项:适配器并不是系统最初的优选设计方案,而是更适用于已投产项目中,由于扩展业务场景,而采取的一种降低修改代码带来的风险的一种补偿方案。所有在已投产的项目中或者接入三方系统时使用适配器模式更容易发挥作用。适配器的侧重点是兼容性。