合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
19.4 适配器模式的扩展 我们刚刚讲的人力资源管理的例子中,其实是一个比较幸运的例子,为什么呢?如果劳动服务公司提供的人员接口不止一个,也就是说,用户基本信息是一个接口,工作信息是一个接口,家庭信息是一个接口,总共有三个接口三个实现类,想想看如何处理呢?不能再使用我们上面的方法了,为什么呢?Java是不支持多继承的,你难道想让OuterUserInfo继承三个实现类?此路不通,再想一个办法,对哦,可以使用类关联的办法嘛!声明一个OuterUserInfo实现类,实现IUserInfo接口,通过再关联其他三个实现类不就可以解决这个问题了吗?是的,是的,好方法,我们先画出类图,如图19-8所示。 OuterUserInfo通过关联的方式与外界的三个实现类通讯,当然也可以理解为是聚合关系。IUserInfo和UserInfo代码如代码清单19-1和代码清单19-2所示,不再赘述。我们来看看拆分后的三个接口和实现类,用户基本信息接口如代码清单19-13所示。 ![](https://box.kancloud.cn/2016-08-14_57b003667e70d.jpg) 图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所示。 ![](https://box.kancloud.cn/2016-08-14_57b003669f1e9.jpg) 图19-9 对象适配器类图 适配器的通用代码也比较简单,把原有的继承关系变更为关联关系就可以了,不再赘述。对象适配器和类适配器的区别是:类适配器是类间继承,对象适配器是对象的合成关系,也可以说是类的关联关系,这是两者的根本区别。二者在实际项目中都会经常用到,由于对象适配器是通过类间的关联关系进行耦合的,因此在设计时就可以做到比较灵活,比如修补源角色的隐形缺陷,关联其他对象等,而类适配器就只能通过覆写源角色的方法进行扩展,在实际项目中,对象适配器使用到场景相对较多。