适配器模式
适配器模式(Adapter Pattern):将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
适配器模式又叫做变压器模式,它也是包装模式(Wrapper)的一种,另一种是装饰模式。
适配器模式就是把一个接口或类转换成其他的接口或类。
如上图,我们要将两个已经成型的模块A和B联系在一起,可以通过引入一个模块C分别适配A和B,然后将ABC拼接到一起,C就是适配器。当然,这也就是适配器模式。
适配器模式的三个角色。
- Target目标角色:该角色定义把其他类转换为何种接口,也就是我们的期望接口。
- Adaptee源角色:要转换成目标角色的角色,它是已经存在的、运行良好的类或对象,经过适配器角色的包装,它会成为一个崭新的角色。
- Adapter适配器角色:适配器模式的核心角色,是需要新建立的,它的职责非常简单:通过继承或类关联的方式,把源角色转换为目标角色。
目标角色Target:
public interface Target {
//目标角色有自己的方法
public void request();
}
目标角色的实现类ConcreteTarget:
public class ConcreteTarget implements Target {
public void request() {
System.out.println("if you need any help,pls call me!");
}
}
源角色Adaptee:
public class Adaptee {
//原有的业务逻辑
public void doSomething(){
System.out.println("I'm kind of busy,leave me alone,pls!");
}
}
适配器角色Adapter:
public class Adapter extends Adaptee implements Target {
public void request() {
super.doSomething();
}
}
场景类Client:
public class Client {
public static void main(String[] args) {
//原有的业务逻辑
Target target = new ConcreteTarget();
target.request();
//现在增加了适配器角色后的业务逻辑
Target target2 = new Adapter();
target2.request();
}
}
适配器模式的优点
- 适配器模式可以让两个没有任何关系的类在一起运行,只要适配器这个角色能够搞定他们就成。
- 增加了类的透明性:访问的是Target目标角色,但是具体的实现都委托给了源角色,而这些对高层次模块是透明的,也是它不需要关心的。
- 提高了类的复用度:源角色在原有的系统中还是可以正常使用,而在目标角色中也可以充当新的演员。
- 灵活性非常好:不想要适配器,删除掉这个适配器就可以,其他的代码都不用修改,基本上就类似一个灵活的构件,想用就用,不想就卸载。
适配器模式的注意事项
- 适配器模式不是为了解决还处在开发阶段的问题,而是解决正在服役的项目问题。
- 适配器模式使用的主要场景是应用扩展,不符合原有设计的时候才考虑通过适配器模式减少代码修改带来的风险。
- 项目一定要遵守依赖倒置原则和里氏替换原则,否则即使在适合使用适配器的场合下,也会带来非常大的改造。
适配器模式的扩展
(1)类适配器:前面通过继承进行的适配都是类适配器。
(2)对象适配器
对象适配器通用类图:
对象适配器和类适配器的区别是:类适配器是类间继承,对象适配器是对象的合成关系,也可以说是类的关联关系,这是两者的根本区别。
适配器模式的实例
我们使用将另一个系统的员工信息,通过适配器的方式连接到我们的系统中。使得通过我们的系统可以直接访问到另一系统的员工信息。
我们的员工信息类图如下:
内部类接口及实现:
public interface IUserInfo {
//获得用户姓名
public String getUserName();
//获得家庭住址
public String getHomeAddress();
//手机号
public String getMobileNumber();
//办公电话
public String getOfficeTelNumber();
//职位
public String getJobPosition();
//家庭电话
public String getHomeTelNumber();
}
import com.sfq.impl.IUserInfo;
public class UserInfo implements IUserInfo {
@Override
public String getUserName() {
System.out.println("瑶瑶");
return null;
}
@Override
public String getHomeAddress() {
System.out.println("家住地球");
return null;
}
@Override
public String getMobileNumber() {
System.out.println("手机号:110");
return null;
}
@Override
public String getOfficeTelNumber() {
System.out.println("办公电话:120");
return null;
}
@Override
public String getJobPosition() {
System.out.println("职位:老板");
return null;
}
@Override
public String getHomeTelNumber() {
System.out.println("家庭电话:119");
return null;
}
}
(1)类适配器
假设对方员工信息类图如下:
我们的对象与该类图的对象都不在一个系统中,我们可以通过RMI实现连接,只要有接口,就可以把远程的对象当成本地的对象使用。
OuterUserInfo实现了IUserInfo接口,还继承了OuterUser,把OuterUser伪装成我们系统中一个IUserInfo对象。这样,我们的系统基本不用修改,所有的人员查询、调用跟本地一样。
注意:我们之所以能够增加一个OuterUserInfo中转类,是因为我们在系统设计时严格遵守了依赖倒置原则和里氏替换原则,否则即使增加了中转类也无法解决问题。
外部接口及实现:
import java.util.Map;
public interface IOuterUser {
//基本信息
public Map getUserBaseInfo();
//工作信息
public Map getUserOfficeInfo();
//家庭信息
public Map getUserHomeInfo();
}
import java.util.HashMap;
import java.util.Map;
import com.sfq.impl.IOuterUser;
public class OuterUser implements IOuterUser {
@Override
public Map getUserBaseInfo() {
HashMap baseInfoMap = new HashMap();
baseInfoMap.put("userName", "朱老四");
baseInfoMap.put("mobileNumber", "手机是:4");
return baseInfoMap;
}
@Override
public Map getUserOfficeInfo() {
HashMap homeInfo = new HashMap();
homeInfo.put("homeTelNumber", "家庭电话:4");
homeInfo.put("homeAddress", "家庭住址:朱圈");
return homeInfo;
}
@Override
public Map getUserHomeInfo() {
HashMap officeInfo = new HashMap();
officeInfo.put("jobPosition", "职位是:老板");
officeInfo.put("officeTelNumber", "办公电话:4");
return officeInfo;
}
}
适配器类实现,实现内部接口,继承外部实现:
import java.util.Map;
import com.sfq.impl.IUserInfo;
public class OuterUserInfo extends OuterUser implements IUserInfo {
private Map baseInfo = super.getUserBaseInfo();
private Map homeInfo = super.getUserHomeInfo();
private Map officeInfo = super.getUserOfficeInfo();
@Override
public String getUserName() {
String userName = (String)this.baseInfo.get("userName");
System.out.println(userName);
return userName;
}
@Override
public String getHomeAddress() {
String homeAddress = (String)this.homeInfo.get("homeAddress");
System.out.println(homeAddress);
return homeAddress;
}
@Override
public String getMobileNumber() {
String mobileNumber = (String)this.baseInfo.get("mobileNumber");
System.out.println(mobileNumber);
return mobileNumber;
}
@Override
public String getOfficeTelNumber() {
String officeTelNumber = (String)this.officeInfo.get("officeTelNumber");
System.out.println(officeTelNumber);
return officeTelNumber;
}
@Override
public String getJobPosition() {
String jobPosition = (String)this.officeInfo.get("jobPosition");
System.out.println(jobPosition);
return jobPosition;
}
@Override
public String getHomeTelNumber() {
String homeTelNumber = (String)this.homeInfo.get("homeTelNumber");
System.out.println(homeTelNumber);
return homeTelNumber;
}
}
场景类,分别访问内部和外部实例:
import com.sfq.action.OuterUserInfo;
import com.sfq.action.UserInfo;
import com.sfq.impl.IUserInfo;
public class Client {
public static void main(String[] args) {
//系统内
System.out.println("-----系统内-----");
IUserInfo youngGirl1 = new UserInfo();
//从数据库中查到2个
for(int i = 0;i < 2;i++) {
youngGirl1.getMobileNumber();
}
//系统外
System.out.println("-----系统外-----");
IUserInfo youngGirl2 = new OuterUserInfo();
//从数据库中查到2个
for(int i = 0;i < 2;i++) {
youngGirl2.getMobileNumber();
}
}
}
结果
-----系统内-----
手机号:110
手机号:110
-----系统外-----
手机是:4
手机是:4
中转的角色有很多的强制类型转换,就是(String)这个东西,如果使用泛型的话,就可以完全避免这个转化。
使用了适配器模式只修改了一句话,其他的业务逻辑都不用修改就解决了系统对接的问题,而且在我们实际系统中只是增加了一个业务类的继承,就实现了可以查本公司的员工信息,也可以查人力资源公司的员工信息,尽量少的修改,通过扩展的方式解决了该问题。
(2)对象适配器
如果人员接口不止一个:用户基本信息是一个接口,工作信息是一个接口,家庭信息是一个接口,总共有三个接口三个实现类,而Java是不支持多继承的。我们可以让OuterUserInfo通过关联的方式与外界的三个实现类通讯。
外部基本信息接口及实现:
import java.util.Map;
public interface IOuterUserBaseInfo {
//基本信息
public Map getUserBaseInfo();
}
import java.util.HashMap;
import java.util.Map;
import com.sfq.impl.IOuterUserBaseInfo;
public class OuterUserBaseInfo implements IOuterUserBaseInfo {
@Override
public Map getUserBaseInfo() {
HashMap baseInfoMap = new HashMap();
baseInfoMap.put("userName", "朱老四");
baseInfoMap.put("mobileNumber", "手机是:4");
return baseInfoMap;
}
}
外部家庭信息接口及实现:
import java.util.Map;
public interface IOuterUserHomeInfo {
//家庭信息
public Map getUserHomeInfo();
}
import java.util.HashMap;
import java.util.Map;
import com.sfq.impl.IOuterUserHomeInfo;
public class OuterUserHomeInfo implements IOuterUserHomeInfo {
@Override
public Map getUserHomeInfo() {
HashMap homeInfo = new HashMap();
homeInfo.put("homeTelNumber", "家庭电话:4");
homeInfo.put("homeAddress", "家庭住址:朱圈");
return homeInfo;
}
}
外部工作信息接口及实现:
import java.util.Map;
public interface IOuterUserOfficeInfo {
//工作信息
public Map getUserOfficeInfo();
}
import java.util.HashMap;
import java.util.Map;
import com.sfq.impl.IOuterUserOfficeInfo;
public class OuterUserOfficeInfo implements IOuterUserOfficeInfo {
@Override
public Map getUserOfficeInfo() {
HashMap officeInfo = new HashMap();
officeInfo.put("jobPosition", "职位是:老板");
officeInfo.put("officeTelNumber", "办公电话:4");
return officeInfo;
}
}
适配器类实现:
import java.util.Map;
import com.sfq.impl.IOuterUserBaseInfo;
import com.sfq.impl.IOuterUserHomeInfo;
import com.sfq.impl.IOuterUserOfficeInfo;
import com.sfq.impl.IUserInfo;
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 OuterUserInfo1(IOuterUserBaseInfo baseInfo, IOuterUserHomeInfo homeInfo, IOuterUserOfficeInfo officeInfo) {
super();
this.baseInfo = baseInfo;
this.homeInfo = homeInfo;
this.officeInfo = officeInfo;
this.baseMap = this.baseInfo.getUserBaseInfo();
this.homeMap = this.homeInfo.getUserHomeInfo();
this.officeMap = this.officeInfo.getUserOfficeInfo();
}
@Override
public String getUserName() {
String userName = (String)this.baseMap.get("userName");
System.out.println(userName);
return userName;
}
@Override
public String getHomeAddress() {
String homeAddress = (String)this.homeMap.get("homeAddress");
System.out.println(homeAddress);
return homeAddress;
}
@Override
public String getMobileNumber() {
String mobileNumber = (String)this.baseMap.get("mobileNumber");
System.out.println(mobileNumber);
return mobileNumber;
}
@Override
public String getOfficeTelNumber() {
String officeTelNumber = (String)this.officeMap.get("officeTelNumber");
System.out.println(officeTelNumber);
return officeTelNumber;
}
@Override
public String getJobPosition() {
String jobPosition = (String)this.officeMap.get("jobPosition");
System.out.println(jobPosition);
return jobPosition;
}
@Override
public String getHomeTelNumber() {
String homeTelNumber = (String)this.homeMap.get("homeTelNumber");
System.out.println(homeTelNumber);
return homeTelNumber;
}
}
场景类Client:
import com.sfq.action.OuterUserBaseInfo;
import com.sfq.action.OuterUserHomeInfo;
import com.sfq.action.OuterUserInfo1;
import com.sfq.action.OuterUserOfficeInfo;
import com.sfq.impl.IOuterUserBaseInfo;
import com.sfq.impl.IOuterUserHomeInfo;
import com.sfq.impl.IOuterUserOfficeInfo;
import com.sfq.impl.IUserInfo;
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);
System.out.println("-----系统外-----");
//从数据库中查到2个
for(int i = 0;i < 2;i++) {
youngGirl.getMobileNumber();
}
}
}