我们刚刚讲的人力资源管理的例子中,其实是一个比较幸运的例子,为什么呢?如果劳动服务公司提供的人员接口不止一个,也就是说,用户基本信息是一个接口,工作信息是一个接口,家庭信息是一个接口,总共有三个接口三个实现类,想想看如何处理呢?不能再使用我们上面的方法了,为什么呢?Java是不支持多继承的,你难道想让OuterUserInfo继承三个实现类?此路不通,再想一个办法,对哦,可以使用类关联的办法嘛!声明一个OuterUserInfo实现类,实现IUserInfo接口,通过再关联其他三个实现类不就可以解决这个问题了吗?是的,是的,好方法,我们先画出类图,如图19-8所示。
OuterUserInfo通过关联的方式与外界的三个实现类通讯,当然也可以理解为是聚合关系。IUserInfo和UserInfo代码如代码清单19-1和代码清单19-2所示,不再赘述。我们来看看拆分后的三个接口和实现类,用户基本信息接口如代码清单19-13所示。
图19-8 拆分接口后的类图
代码清单19-13 用户基本信息接口
public interface IOuterUserBaseInfo { //基本信息,比如名称、性别、手机号码等 public Map getUserBaseInfo;}
用户家庭信息接口如代码清单19-14所示。
代码清单19-14 用户家庭信息接口
public interface IOuterUserHomeInfo { //用户的家庭信息 public Map getUserHomeInfo;}
用户工作信息接口如代码清单19-15所示。
代码清单19-15 用户工作信息接口
public interface IOuterUserOfficeInfo { //工作区域信息 public Map getUserOfficeInfo;}
读到这里,读者应该想到这样一个问题:系统这样设计是否合理呢?合理,绝对合理!想想单一职责原则是怎么说的,类和接口要保持职责单一,在实际的应用中类可以有多重职责,但是接口一定要职责单一,因此,我们上面拆分接口的假想也是非常合乎逻辑的。我们来看三个相关的实现类,用户基本信息如代码清单19-16所示。
代码清单19-16 用户基本信息
public class OuterUserBaseInfo implements IOuterUserBaseInfo { /* * 用户的基本信息 */ public Map getUserBaseInfo { HashMap baseInfoMap = new HashMap; baseInfoMap.put(/"userName/", /"这个员工叫混世魔王.../"); baseInfoMap.put(/"mobileNumber/", /"这个员工电话是.../"); return baseInfoMap; }}
用户家庭信息如代码清单19-17所示。
代码清单19-17 用户家庭信息
public class OuterUserHomeInfo implements IOuterUserHomeInfo { /* * 员工的家庭信息 */ public Map getUserHomeInfo { HashMap homeInfo = new HashMap; homeInfo.put(/"homeTelNumbner/", /"员工的家庭电话是.../"); homeInfo.put(/"homeAddress/", /"员工的家庭地址是.../"); return homeInfo; }}
用户工作信息如代码清单19-18所示。
代码清单19-18 用户工作信息
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 适配器
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 场景类
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); //从数据库中查到101个 for(int i=0;i<101;i++){ youngGirl.getMobileNumber; }}}
运行的结果还是相同的。大家想想看,OuterUserInfo变成了委托服务,把IUserInfo接口需要的所有的操作都委托给其他三个接口下的实现类,它的委托是通过对象层次的关联关系进行委托的,而不是继承关系。好了,讲了这么多,我们需要给这种适配器起个名字,就是对象适配器,我们之前讲的通过继承进行的适配,叫做类适配器。对象适配器的通用类图,如图19-9所示。
图19-9 对象适配器类图
适配器的通用代码也比较简单,把原有的继承关系变更为关联关系就可以了,不再赘述。对象适配器和类适配器的区别是:类适配器是类间继承,对象适配器是对象的合成关系,也可以说是类的关联关系,这是两者的根本区别。二者在实际项目中都会经常用到,由于对象适配器是通过类间的关联关系进行耦合的,因此在设计时就可以做到比较灵活,比如修补源角色的隐形缺陷,关联其他对象等,而类适配器就只能通过覆写源角色的方法进行扩展,在实际项目中,对象适配器使用到场景相对较多。