一、适配器模式概述:
适配器模式不是在设计阶段考虑的,而是在系统服役阶段使用的,通常用于拓展新需求。这个模式跟装饰模式类似,都是做了一个包装,只不过该**模式的定义是将一个类的接口变换成客户端所期待的另一种接口, 从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。**在实际应用中,适配器分为类适配器和对象适配器。
二、类适配器及其demo:
图中的adapter就是适配器,其本质相当于一个插件或者中间件,将原本两个不一样的接口进行整合对接,target就是最终要整合成的接口,adaptee就是被整合对象,在实际项目中,通常是第三方的接口。在这个图中,我们有注意到被整合的对象adaptee只有一个接口或者类,所以,这种模式的场景的适配器我们称之为类适配器。
demo场景描述:假设我们有一套自己的员工管理系统,然后现在招募了外包人员,但是外包人员也有自己公司的管理系统,为了在我们的系统上也能及时的查询外包员工的相关信息,我们需要将他们的信息也纳入到我们的系统中,但是,因为接口不一致,所以,这个时候,就需要使用适配器来进行对接了。
员工系统首先要有员工信息接口及实现类:
/** 员工信息接口 */
interface IUserInfo {
//获得用户姓名
public String getUserName();
//获得家庭地址
public String getHomeAddress();
//手机号码, 这个太重要, 手机泛滥呀
public String getMobileNumber();
//办公电话, 一般是座机
public String getOfficeTelNumber();
//这个人的职位是什么
public String getJobPosition();
//获得家庭电话, 这有点不好, 我不喜欢打家庭电话讨论工作
public String getHomeTelNumber();
}
/** 员工信息实现类 */
class UserInfo implements IUserInfo {
/*
* 获得家庭地址, 下属送礼也可以找到地方
*/
public String getHomeAddress() {
System.out.println("这里是员工的家庭地址...");
return null;
}
/** 获得家庭电话号码 */
public String getHomeTelNumber() {
System.out.println("员工的家庭电话是...");
return null;
}
/** 员工的职位, 是部门经理还是普通职员 */
public String getJobPosition() {
System.out.println("这个人的职位是BOSS...");
return null;
}
/** 手机号码 */
public String getMobileNumber() {
System.out.println("这个人的手机号码是0000...");
return null;
}
/** 办公室电话, 烦躁的时候最好"不小心"把电话线踢掉 */
public String getOfficeTelNumber() {
System.out.println("办公室电话是...");
return null;
}
/** 姓名, 这个很重要 */
public String getUserName() {System.out.println("姓名叫做...");
return null;
}
}
外包员工信息的接口及实现类:
/** 外包员工信息接口 */
interface IOuterUser {
//基本信息, 比如名称、 性别、 手机号码等
public Map getUserBaseInfo();
//工作区域信息
public Map getUserOfficeInfo();
//用户的家庭信息
public Map getUserHomeInfo();
}
/** 外包员工信息具体类 */
class OuterUser implements IOuterUser {
/** 用户的基本信息 */
public Map getUserBaseInfo() {
HashMap baseInfoMap = new HashMap();
baseInfoMap.put("userName", "这个员工叫混世魔王...");
baseInfoMap.put("mobileNumber", "这个员工电话是...");
return baseInfoMap;
}
/** 员工的家庭信息 */
public Map getUserHomeInfo() {
HashMap homeInfo = new HashMap();
homeInfo.put("homeTelNumbner", "员工的家庭电话是...");
homeInfo.put("homeAddress", "员工的家庭地址是...");
return homeInfo;
}
/** 员工的工作信息, 比如, 职位等 */
public Map getUserOfficeInfo() {
HashMap officeInfo = new HashMap();
officeInfo.put("jobPosition","这个人的职位是BOSS...");
officeInfo.put("officeTelNumber", "员工的办公电话是...");
return officeInfo;
}
}
target和adaptee都有了,那么接下来就是适配器了:
/** 核心:适配器 */
class OuterUserInfo extends OuterUser implements IUserInfo {
private Map baseInfo = super.getUserBaseInfo(); //员工的基本信息
private Map homeInfo = super.getUserHomeInfo(); //员工的家庭信息
private Map officeInfo = super.getUserOfficeInfo(); //工作信息
/** 家庭地址 */
public String getHomeAddress() {
String homeAddress = (String)this.homeInfo.get("homeAddress");
System.out.println(homeAddress);
return homeAddress;
}
/** 家庭电话号码 */
public String getHomeTelNumber() {
String homeTelNumber = (String)this.homeInfo.get("homeTelNumber");
System.out.println(homeTelNumber);
return homeTelNumber;
}
/** 职位信息 */
public String getJobPosition() {
String jobPosition = (String)this.officeInfo.get("jobPosition");
System.out.println(jobPosition);
return jobPosition;
}
/** 手机号码 */
public String getMobileNumber() {
String mobileNumber = (String)this.baseInfo.get("mobileNumber");
System.out.println(mobileNumber);
return mobileNumber;
}
/** 办公电话 */
public String getOfficeTelNumber() {
String officeTelNumber = (String)this.officeInfo.get("officeTelNumbe");
System.out.println(officeTelNumber);
return officeTelNumber;
}
/** 员工的名称 */
public String getUserName() {
String userName = (String)this.baseInfo.get("userName");
System.out.println(userName);
return userName;
}
}
适配器的实现很简单,就是将adaptee中的对象信息一一获取出来,然后填入到target的类对象中。
client端的实现:
public class AdapterDesign {
public static void main(String[] args) {
/* 调用外包人员信息 */
IUserInfo youngGirl = new OuterUserInfo();
/* 从数据库中查到101个 */
for(int i = 0; i < 101; i++){
youngGirl.getMobileNumber();
}
}
}
三、对象适配器及其demo:
java中不支持类的多继承,实际的问题处理中,我们的adaptee是不止一个接口的,那么,被适配的对象也就不止一个了,适配器的设计肯定就不能以继承的方式来实现。将原来的继承方式改为了直接关系,对象适配器和类适配器的区别是:类适配器是类间继承, 对象适配器是对象的合成关系,也可以说是类的关联关系,这是两者的根本区别。
demo场景:
和类适配器场景相似,只不过我们将adaptee改为多个接口,那么就有了多个类对象,从而修改适配器的实现。
公司员工管理系统还是保持不变:
/** 员工信息接口 */
interface IUserInfo {
//获得用户姓名
public String getUserName();
//获得家庭地址
public String getHomeAddress();
//手机号码, 这个太重要, 手机泛滥呀
public String getMobileNumber();
//办公电话, 一般是座机
public String getOfficeTelNumber();
//这个人的职位是什么
public String getJobPosition();
//获得家庭电话, 这有点不好, 我不喜欢打家庭电话讨论工作
public String getHomeTelNumber();
}
/** 员工信息实现类 */
class UserInfo implements IUserInfo {
/*
* 获得家庭地址, 下属送礼也可以找到地方
*/
public String getHomeAddress() {
System.out.println("这里是员工的家庭地址...");
return null;
}
/** 获得家庭电话号码 */
public String getHomeTelNumber() {
System.out.println("员工的家庭电话是...");
return null;
}
/** 员工的职位, 是部门经理还是普通职员 */
public String getJobPosition() {
System.out.println("这个人的职位是BOSS...");
return null;
}
/** 手机号码 */
public String getMobileNumber() {
System.out.println("这个人的手机号码是0000...");
return null;
}
/** 办公室电话, 烦躁的时候最好"不小心"把电话线踢掉 */
public String getOfficeTelNumber() {
System.out.println("办公室电话是...");
return null;
}
/** 姓名, 这个很重要 */
public String getUserName() {System.out.println("姓名叫做...");
return null;
}
}
外包员工的信息进行了改变,拓展为了三个接口和三个实现类:
/** 外包员工基本信息接口 */
interface IOuterUserBaseInfo {
//基本信息, 比如名称、 性别、 手机号码等
public Map getUserBaseInfo();
}
/** 外包员工基本信息实现类 */
class OuterUserBaseInfo implements IOuterUserBaseInfo {
/*
* 用户的基本信息
*/
public Map getUserBaseInfo() {
HashMap baseInfoMap = new HashMap();
baseInfoMap.put("userName", "这个员工叫混世魔王...");
baseInfoMap.put("mobileNumber", "这个员工电话是...");
return baseInfoMap;
}
}
/** 外包员工家庭信息接口 */
interface IOuterUserHomeInfo {
//用户的家庭信息
public Map getUserHomeInfo();
}
/** 外包员工家庭信息实现类 */
class OuterUserHomeInfo implements IOuterUserHomeInfo {
/*
* 员工的家庭信息
*/
public Map getUserHomeInfo() {
HashMap homeInfo = new HashMap();
homeInfo.put("homeTelNumbner", "员工的家庭电话是...");
homeInfo.put("homeAddress", "员工的家庭地址是...");
return homeInfo;
}
}
/** 外包员工工作信息接口 */
interface IOuterUserOfficeInfo {
//工作区域信息
public Map getUserOfficeInfo();
}
/** 外包员工工作信息实现类 */
class OuterUserOfficeInfo implements IOuterUserOfficeInfo {
/*
* 员工的工作信息, 比如, 职位等
*/
public Map getUserOfficeInfo() {
HashMap officeInfo = new HashMap();
officeInfo.put("jobPosition","这个人的职位是BOSS...");
officeInfo.put("officeTelNumber", "员工的办公电话是...");
return officeInfo;
}
}
适配器的实现:
/** 适配器 */
class OuterUserInfo implements IUserInfo {
//源目标对象
private IOuterUserBaseInfo baseInfo = null; //员工的基本信息
private IOuterUserHomeInfo homeInfo = null; //员工的家庭信息
private IOuterUserOfficeInfo officeInfo = null; //工作信息
//数据处理
private Map baseMap = null;
private Map homeMap = null;
private Map officeMap = null;
//构造函数传递对象
public OuterUserInfo(IOuterUserBaseInfo baseInfo,IOuterUserHomeInfo homeInfo, IOuterUserOfficeInfo officeInfo){
this.baseInfo = baseInfo;
this.homeInfo = homeInfo;
this.officeInfo = officeInfo;
//数据处理
this.baseMap = this.baseInfo.getUserBaseInfo();
this.homeMap = this.homeInfo.getUserHomeInfo();
this.officeMap = this.officeInfo.getUserOfficeInfo();
}
//家庭地址
public String getHomeAddress() {
String homeAddress = (String)this.homeMap.get("homeAddress");
System.out.println(homeAddress);
return homeAddress;
}
//家庭电话号码
public String getHomeTelNumber() {
String homeTelNumber = (String)this.homeMap.get("homeTelNumber");
System.out.println(homeTelNumber);
return homeTelNumber;
}
//职位信息
public String getJobPosition() {
String jobPosition = (String)this.officeMap.get("jobPosition");
System.out.println(jobPosition);
return jobPosition;
}
//手机号码
public String getMobileNumber() {
String mobileNumber = (String)this.baseMap.get("mobileNumber");
System.out.println(mobileNumber);
return mobileNumber;
}
//办公电话
public String getOfficeTelNumber() {
String officeTelNumber= (String)this.officeMap.get("officeTelNumber");
System.out.println(officeTelNumber);
return officeTelNumber;
}
// 员工的名称
public String getUserName() {
String userName = (String)this.baseMap.get("userName");
System.out.println(userName);
return userName;
}
}
适配器只实现target的接口了,而不再继承adaptee的类。
再看下client端的测试代码:
public class AdapterHeDesign {
public static void main(String[] args) {
//外系统的人员信息
IOuterUserBaseInfo baseInfo = new OuterUserBaseInfo();
IOuterUserHomeInfo homeInfo = new OuterUserHomeInfo();
IOuterUserOfficeInfo officeInfo = new OuterUserOfficeInfo();
//传递三个对象
IUserInfo youngGirl = new OuterUserInfo(baseInfo,homeInfo,officeInfo);
//从数据库中查到10个
for(int i=0;i<10;i++){
youngGirl.getMobileNumber();
}
}
}
可以看到,类适配器和对象适配器的关键点就在于适配的继承上面,是否考虑继承adaptee的类。
博客参考书籍:秦小波 《设计模式之禅(第2版)》