定义:
将一个类的接口变成客户端所期待的另一种接口,从而使原本因为接口不匹配而无法在一起工作的两个类能够在一起工作。
适配器模式有两种表现形式,一种称作“类适配器”,一种称作“对象适配器”。在本文中将举一个“本公司员工和外来公司员工”这样的一个例子,本公司员工的信息是由本公司的系统来维护的,但是外来公司员工的信息是在他们自己的公司中维护的,但是现在要将外来员工的信息整合到本公司的员工管理系统中,但是由于两个公司开发的系统接口并不统一,没办法实现整合,所以用到了适配器的模式,将外来公司的员工的信息类采用适配器模式将其转换成本公司相符合的接口,这样就可以整合了,由于两个公司的实现员工信息的接口,都是使用一个接口来抽象的,所以这里用“类适配器”,就可以了,其类图如下:
实现的源代码如下:
public interface IUserInfo {
//个人基本信息
public String getUserName();
public String getMobileNumber();
//个人家庭信息
public String getHomeAddress();
public String getHomeTelNumber();
//个人公司信息
public String getJobPosition();
public String getOfficeNumber();
}
//这里就是普通的POJO,但是为了模拟,所以这里返回的时候都是返回了一个随机的字符串
public class UserInfo implements IUserInfo {
@Override
public String getUserName() {
return Tool.getRandString(5);
}
@Override
public String getMobileNumber() {
return Tool.getRandNumber(11);
}
@Override
public String getHomeAddress() {
return Tool.getRandString(10);
}
@Override
public String getHomeTelNumber() {
return Tool.getRandNumber(11);
}
@Override
public String getJobPosition() {
return Tool.getRandString(7);
}
@Override
public String getOfficeNumber() {
return Tool.getRandNumber(11);
}
}
public interface IOuterUserInfo {
public Map getUserBaseInfo();
public Map getUserOfficeInfo();
public Map getUserHomeInfo();
}
public class OuterUserInfo implements IOuterUserInfo {
//外来员工的基本信息
@SuppressWarnings("rawtypes")
@Override
public Map getUserBaseInfo() {
HashMap<String, String> baseInfoMap=new HashMap<String,String>();
baseInfoMap.put("username", Tool.getRandString(5));
baseInfoMap.put("mobileNumber", Tool.getRandNumber(11));
return baseInfoMap;
}
//外来员工的公司信息
@SuppressWarnings("rawtypes")
@Override
public Map getUserOfficeInfo() {
HashMap<String, String> officeInfoMap=new HashMap<String,String>();
officeInfoMap.put("jobPosition", Tool.getRandString(7));
officeInfoMap.put("officeNumber", Tool.getRandNumber(11));
return officeInfoMap;
}
//外来员工的家庭信息
@SuppressWarnings("rawtypes")
@Override
public Map getUserHomeInfo() {
HashMap<String, String> homeInfoMap=new HashMap<String,String>();
homeInfoMap.put("homeAddress", Tool.getRandString(10));
homeInfoMap.put("homeNumber", Tool.getRandNumber(11));
return homeInfoMap;
}
}
/*
* 类适配器,实现了目标接口的接口,继承了要转换的类
*/
public class AdapterOuterUser extends OuterUserInfo implements IUserInfo {
//从父类获得信息
private Map baseInfo=super.getUserBaseInfo();
private Map homeInfo=super.getUserHomeInfo();
private Map officeInfo=super.getUserOfficeInfo();
@Override
public String getUserName() {
return (String)baseInfo.get("username");
}
@Override
public String getMobileNumber() {
return (String)baseInfo.get("mobileNumber");
}
@Override
public String getHomeAddress() {
return (String)homeInfo.get("homeAddress");
}
@Override
public String getHomeTelNumber() {
return (String)homeInfo.get("homeNumber");
}
@Override
public String getJobPosition() {
return (String)officeInfo.get("jobPosition");
}
@Override
public String getOfficeNumber() {
return (String)officeInfo.get("officeNumber");
}
}
public class Client {
public static void main(String[] args) {
//本公司员工信息
IUserInfo selfUser=new UserInfo();
System.out.println(selfUser.getUserName()+" "+selfUser.getMobileNumber());
System.out.println();
//外来员工信息
IUserInfo outerUser=new AdapterOuterUser();
System.out.println(outerUser.getUserName()+" "+outerUser.getHomeTelNumber());
}
}
上面讲解的是类适配器,用类适配器的原因在于两个公司的员工信息都是用一个接口抽象的,如果其中一个公司人家员工信息抽象的是好几个接口,比如说上面外来公司如果员工信息抽象了三个接口,那怎么办?尤其是java,java不支持多继承,所以就有了另外一种解决方案:对象适配器,看如下类图:
其实现代码如下(IUserInfo和UserInfo和上面一样,这里就不重复了):
public interface IOuterUserBaseInfo {
public Map getUserBaseInfo();
}
public interface IOuterUserHomeInfo {
public Map getUserHomeInfo();
}
public interface IOuterUserOfficeInfo {
public Map getUserOfficeInfo();
}
public class OuterUserBaseInfo implements IOuterUserBaseInfo {
@Override
public Map getUserBaseInfo() {
HashMap<String, String> baseInfoMap=new HashMap<String,String>();
baseInfoMap.put("username", Tool.getRandString(5));
baseInfoMap.put("mobileNumber", Tool.getRandNumber(11));
return baseInfoMap;
}
}
public class OuterUserHomeInfo implements IOuterUserHomeInfo {
@Override
public Map getUserHomeInfo() {
HashMap<String, String> homeInfoMap=new HashMap<String,String>();
homeInfoMap.put("homeAddress", Tool.getRandString(10));
homeInfoMap.put("homeNumber", Tool.getRandNumber(11));
return homeInfoMap;
}
}
public class OuterUserOfficeInfo implements IOuterUserOfficeInfo {
@Override
public Map getUserOfficeInfo() {
HashMap<String, String> officeInfoMap=new HashMap<String,String>();
officeInfoMap.put("jobPosition", Tool.getRandString(7));
officeInfoMap.put("officeNumber", Tool.getRandNumber(11));
return officeInfoMap;
}
}
/*
* 对象适配器,实现了目标接口的接口,并把源目标对象作为成员变量
*/
public class AdapterOuterUser implements IUserInfo {
//源目标对象
private IOuterUserBaseInfo baseInfoObj=null;
private IOuterUserHomeInfo homeInfoObj=null;
private IOuterUserOfficeInfo officeInfoObj=null;
//数据处理
private Map baseInfo=null;
private Map homeInfo=null;
private Map officeInfo=null;
public AdapterOuterUser(IOuterUserBaseInfo baseInfoObj,
IOuterUserHomeInfo homeInfoObj, IOuterUserOfficeInfo officeInfoObj) {
this.baseInfoObj = baseInfoObj;
this.homeInfoObj = homeInfoObj;
this.officeInfoObj = officeInfoObj;
//数据处理
this.baseInfo=baseInfoObj.getUserBaseInfo();
this.homeInfo=homeInfoObj.getUserHomeInfo();
this.officeInfo=officeInfoObj.getUserOfficeInfo();
}
@Override
public String getUserName() {
return (String)baseInfo.get("username");
}
@Override
public String getMobileNumber() {
return (String)baseInfo.get("mobileNumber");
}
@Override
public String getHomeAddress() {
return (String)homeInfo.get("homeAddress");
}
@Override
public String getHomeTelNumber() {
return (String)homeInfo.get("homeNumber");
}
@Override
public String getJobPosition() {
return (String)officeInfo.get("jobPosition");
}
@Override
public String getOfficeNumber() {
return (String)officeInfo.get("officeNumber");
}
}
public class Client {
public static void main(String[] args) {
//本公司员工信息
IUserInfo selfUser=new UserInfo();
System.out.println(selfUser.getUserName()+" "+selfUser.getMobileNumber());
System.out.println();
//外来员工信息
IOuterUserBaseInfo baseInfo=new OuterUserBaseInfo();
IOuterUserHomeInfo homeInfo=new OuterUserHomeInfo();
IOuterUserOfficeInfo officeInfo=new OuterUserOfficeInfo();
IUserInfo outerUser=new AdapterOuterUser(baseInfo,homeInfo,officeInfo);
System.out.println(outerUser.getUserName()+" "+outerUser.getHomeTelNumber());
}
}
适配器模式的优点:
1、适配器可以让两个没有任何关系的类在一起运行。
2、增加了类的透明性
3、提高了类的复用度
4、灵活性非常好,当不想要适配器时,直接删掉就可以了,其他的代码几乎不用修改。
体会:
适配器模式就是在增加或修改一个已经投产中的产品时,若发现新增的类或是从外部导入的类不符合本系统的接口,则可以使用适配器模式解决这个问题,避免了直接修改接口这个高危险的动作。
适配器模式可以发挥它的独特的魅力,其中很重要的一个原因就是原因的系统严格的遵守了依赖倒置原则,即是严格的面向接口编程,才使系统有这么大的“肚量”,这里也很好的体现了依赖倒置原则的重要性。