19.4 适配器模式的扩展
我们刚刚讲的人力资源管理的例子中,其实是一个比较幸运的例子,为什么呢?如果劳动服务公司提供的人员接口不止一个,也就是说,用户基本信息是一个接口,工作信息是一个接口,家庭信息是一个接口,总共有三个接口三个实现类,想想看如何处理呢?不能再使用我们上面的方法了,为什么呢?Java是不支持多继承的,你难道想让OuterUserInfo继承三个实现类?此路不通,再想一个办法,对哦,可以使用类关联的办法嘛!声明一个OuterUserInfo实现类,实现IUserInfo接口,通过再关联其他三个实现类不就可以解决这个问题了吗?是的,是的,好方法,我们先画出类图,如图19-8所示。
OuterUserInfo通过关联的方式与外界的三个实现类通讯,当然也可以理解为是聚合关系。IUserInfo和UserInfo代码如代码清单19-1和代码清单19-2所示,不再赘述。我们来看看拆分后的三个接口和实现类,用户基本信息接口如代码清单19-13所示。
图19-8 拆分接口后的类图
代码清单19-13 用户基本信息接口
1 2 3 4
| public interface IOuterUserBaseInfo { public Map getUserBaseInfo(); }
|
用户家庭信息接口如代码清单19-14所示。
代码清单19-14 用户家庭信息接口
1 2 3 4 5
| public interface IOuterUserHomeInfo { public Map getUserHomeInfo(); }
|
用户工作信息接口如代码清单19-15所示。
代码清单19-15 用户工作信息接口
1 2 3 4
| public interface IOuterUserOfficeInfo { public Map getUserOfficeInfo(); }
|
读到这里,读者应该想到这样一个问题:系统这样设计是否合理呢?合理,绝对合理! 想想单一职责原则是怎么说的,类和接口要保持职责单一,在实际的应用中类可以有多重职责,但是接口一定要职责单一,因此,我们上面拆分接口的假想也是非常合乎逻辑的。我们来看三个相关的实现类,用户基本信息如代码清单19-16所示。
代码清单19-16 用户基本信息
1 2 3 4 5 6 7 8 9 10 11
| public class OuterUserBaseInfo implements IOuterUserBaseInfo {
public Map getUserBaseInfo() { HashMap baseInfoMap = new HashMap(); baseInfoMap.put("userName", "这个员工叫混世魔王..."); baseInfoMap.put("mobileNumber", "这个员工电话是..."); return baseInfoMap; } }
|
用户家庭信息如代码清单19-17所示。
代码清单19-17 用户家庭信息
1 2 3 4 5 6 7 8 9 10 11
| public class OuterUserHomeInfo implements IOuterUserHomeInfo {
public Map getUserHomeInfo() { HashMap homeInfo = new HashMap(); homeInfo.put("homeTelNumbner", "员工的家庭电话是..."); homeInfo.put("homeAddress", "员工的家庭地址是..."); return homeInfo; } }
|
用户工作信息如代码清单19-18所示。
代码清单19-18 用户工作信息
1 2 3 4 5 6 7 8 9 10 11
| public class OuterUserOfficeInfo implements IOuterUserOfficeInfo {
public Map getUserOfficeInfo() { HashMap officeInfo = new HashMap(); officeInfo.put("jobPosition","这个人的职位是BOSS..."); officeInfo.put("officeTelNumber", "员工的办公电话是..."); return officeInfo; } }
|
这里又到我们的核心了——适配器。好,我们来看适配器代码,如代码清单19-19所示。
代码清单19-19 适配器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| public 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; } }
|
大家只要注意一下黑色字体的构造函数就可以了,它接收三个对象,其他部分变化不大,只是变量名称进行了修改,我们再来看场景类,如代码清单19-20所示。
代码清单19-20 场景类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Client { 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); for(int i=0;i<101;i++){ youngGirl.getMobileNumber(); } } }
|
运行的结果还是相同的。大家想想看,OuterUserInfo变成了委托服务,把IUserInfo接口需要的所有的操作都委托给其他三个接口下的实现类,它的委托是通过对象层次的关联关系进行委托的,而不是继承关系。好了,讲了这么多,我们需要给这种适配器起个名字,就是对象适配器,我们之前讲的通过继承进行的适配,叫做类适配器。对象适配器的通用类图, 如图19-9所示。
图19-9 对象适配器类图
适配器的通用代码也比较简单,把原有的继承关系变更为关联关系就可以了,不再赘述。对象适配器和类适配器的区别是:类适配器是类间继承,对象适配器是对象的合成关系,也可以说是类的关联关系,这是两者的根本区别。二者在实际项目中都会经常用到,由于对象适配器是通过类间的关联关系进行耦合的,因此在设计时就可以做到比较灵活,比如修补源角色的隐形缺陷,关联其他对象等,而类适配器就只能通过覆写源角色的方法进行扩展,在实际项目中,对象适配器使用到场景相对较多。