程序员人生 网站导航

设计模式--适配器模式【 Adapter Pattern】

栏目:框架设计时间:2016-02-29 16:57:55

适配器模式,这个模式也很简单,你笔记本上的那个拖在外面的黑盒子就是个适配器,1般你在中国能用,在日本也能用,虽然两个国家的的电源电压不同,中国是 220V,日本是 110V,但是这个适配器能够把这些不同的电压转换为你需要的 36V 电压,保证你的笔记本能够正常运行,那我们在设计模式中引入这个适配器模式是否是也是这个意思呢?是的,1样的作用,两个不同接口,有不同的实现,但是某1天突然上帝命令你把 B 接口转换为 A 接口,怎样办?继承,能解决,但是比较傻,而且还背背了 OCP 原则,怎样办?好在我们还有适配器模式。

适配器的通用类图是这个模样滴:
这里写图片描述

Target 是1个类(接口) ,Adaptee 是1个接口,通过 Adapter 把 Adaptee 包装成 Target 的1个子类(实现类) ,注意了这里用了个名词包装(Wrapper) ,那其实这个模式也叫做包装模式(Wrapper),但是包装模式可不知1个,还包括了以后要讲的装潢模式。我来说个自己的1个经验,让大家可以更容易了解这个适配器模式,否则纯讲技术太枯燥了,技术也能够有文娱的嘛。

我在 2004 年的时候带了1个项目,做1个人力资源管理,该项目是我们总公司发起的项目,公司1共有 700 多号人,包括子公司,这个项目还是比较简单的,分为3大模块:人员信息管理,薪酬管理,职位管理,其中人员管理这块就用到了适配器模式,是怎样回事呢?当时开发时明确的指明:人员信息简管理的对象是所有员工的所有信息,然后我们就这样设计了1个类图:
这里写图片描述

还是比较简单的,有1个对象 UserInfo 存储用户的所有信息(实际系统上还有很多子类,不多说了),也就是BO(Business Object) ,这个 UserInfo 对象,在系统中很多地方使用,你可以查看自己的信息,也能够做修改,固然这个对象是有 setter 方法的,我们这里用不到就隐藏掉了。

这个项目是 04 年年底投产的,运行到 05 年年底还是比较安稳的,中间修修补补也很正常,05 年年底不知道是那股风吹的,很多公司开始使用借聘人员的方式招聘人员,我们公司也不例外,从1个人力资源公司借用了1大批的低技术、低工资的人员,分配到各个子公司,总共有将近 200 号人,然后就找我们部门老大谈判,说要增加1个功能借用人员管理,老大1看有钱赚呀,1拍大腿,做!

我带人过去1调研,不是这么简单,人力资源公司有1套自己的人员管理系统,我们公司需要把我们使用到的人员信息传输到我们的系统中,系统之间的传输使用 RMI(Remote Method Invocation,远程对象调用)的方式,但是有1个问题人力资源公司的人员对象和我们系统的对象不相同呀,他们的对象是这样的:
这里写图片描述

人员资源公司是把人的信息分为了3部份: 基本信息, 办公信息和个人家庭信息, 并且都放到了 HashMap中,比如人员的姓名放到 BaseInfo信息中,家庭地址放到 HomeInfo 中,这咱不好说他们系统设计的不好,那问题是咱的系统要和他们系统有交互,怎样办?使用适配器模式,类图以下:
这里写图片描述

大家可能会问,这两个对象都不在1个系统中,你如何使用呢?简单!RMI 已帮我们做了这件事情,只要有接口,就能够把远程的对象当做本地的对象使用,这个大家有时间可以去看1下 RMI 文档,不多说了。通过适配器,把 OuterUser 假装成我们系统中1个 IUserInfo 对象,这样,我们的系统基本不用修改甚么程序,所有的人员查询、调用跟本地1样样的,说的口干舌燥,那下边我们来看具体的代码实现:

首先看 IUserInfo.java 的代码:

public interface IUserInfo { //取得用户姓名 public String getUserName(); //取得家庭地址 public String getHomeAddress(); //手机号码,这个太重要,手机泛滥呀 public String getMobileNumber(); //办公电话,1般式座机 public String getOfficeTelNumber(); //这个人的职位是啥 public String getJobPosition(); //取得家庭电话,这个有点缺德,我是不喜欢打家庭电话讨论工作 public String getHomeTelNumber(); }

然后看这个接口的实现类:

public 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; } }

可能有人要问了,为何要把电话号码、手机号码都设置成 String 类型,而不是 int 类型,大家觉的呢?题外话,这个绝对应当是 String 类型,包括数据库也应当是 varchar 类型的,手机号码有小灵通带区号的,比如 02100001,这个你用数字怎样表示?有些人要在手机号码前加上 0086 后再保存,比如我们公司的印度阿3就是这样,喜欢在手机号码前 0086保存下来,呵呵,我是想到啥就说啥,

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐