1.定义
将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
适配器模式又叫做变压器模式。
2.适配器模式的应用场景
适配器模式应用的场景只要记住一点就足够了:你有动机修改一个已经投产中的接口时,适配器模式可能是最适合你的模式。比如系统扩展了,需要使用一个已有或新建立的类,但这个类又不符合系统的接口,怎么办?使用适配器模式。
日常生活中也是经常能见到这样的模式的,相信很多人都知道什么是显卡,也有很多人知道显卡的本名——图形适配器。我们知道显示器是用来显示图形的,它是不能显示数据,它只能够接受来自图形发送设备的信号。可是我们手头上只有CPU这个产生各种描述图形的数据的数据发送器。我们需要将这些数据让显示器进行显示,可是这两个部件却是不兼容的。于是我们需要一个 中间设备,它能够将CPU“适配”于显示器,这便是我们的显卡——图形适配器(Adapter)。
下面来看一个例子:
在我们日常开发中,经常要碰到和别的系统集成的问题。有时候两个系统中描述同一个事物的Class定义却不一样,
比如我自己系统中的User对象是这样定义的:
package _13AdapterPattern;
/**
* 目标系统的用户接口
*/
public interface IUserInfo {
public String getName();
public String getCompanyAddress();
}
package _13AdapterPattern;
/**
* 目标系统的用户实现类
*/
public class TargetUserInfo implements IUserInfo {
@Override
public String getName() {
System.out.println("张三");
return null;
}
@Override
public String getCompanyAddress() {
System.out.println("杭州");
return null;
}
}
而我要对接的第三方系统的用户设计是这样:
package _13AdapterPattern;
import java.util.HashMap;
import java.util.Map;
/**
* 第三方系统的用户定义
*/
public class SourceUserInfo {
private Map<String, String> userInfoMap = new HashMap<String, String>();
public SourceUserInfo()
{
userInfoMap.put("userName", "张三");
userInfoMap.put("companyAddress", "杭州");
}
public String getUserInfo(String key)
{
return userInfoMap.get(key);
}
}
这时候如果我调用第三方系统的webservice得到的用户对象在我们系统中将不能运行,因为我们定义的完全不同。
那么这时候该怎么办呢?
好吧,这个时候我想到去继承它们的用户类,并且实现自己的接口,这样在拿到它们数据的同时,还能改装成自己的用户类:
package _13AdapterPattern;
/**
* 适配器类,将第三方的用户改装成自己的用户类
*/
public class AdapterUserInfo extends SourceUserInfo implements IUserInfo {
@Override
public String getName() {
// 将他们的获取用户信息的API 封装到我们自己的API中实现适配器
return this.getUserInfo("userName");
}
@Override
public String getCompanyAddress() {
// TODO Auto-generated method stub
return this.getUserInfo("companyAddress");
}
}
这个AdapterUserInfo就是一个简单实现的适配器。
3.适配器模式的三个角色
- Target目标角色
- Adaptee源角色
- Adapter适配器角色
4.适配器模式的优点
- 适配器模式可以让两个没有任何关系的类在一起运行,只要适配器这个角色能够搞定它们就行。
- 增加了类的透明性:想想看,我们访问的目标角色,但是具体的实现都委托给了源角色,而这些对高层模块是透明的,也是它不需要关心的。
- 提高了类的复用度:源角色在原有的系统中还是可以正常使用,而在目标角色中也可以充当新的演员。
- 灵活性非常好:不想使用适配器的时候,只要删除适配器就行了,其他代码基本不用修改。
5.适配器模式的注意事项
适配器模式最好在详细设计阶段不要考虑它,它不是为了解决还在开发阶段的问题,而是解决正在服役的项目问题,没有一个系统分析师会在做详细设计的时候考虑使用适配器模式。这个模式的主要使用场景是扩展应用中。
6.适配器模式的扩展
适配器模式分为两种
- 类型适配器:就是上面实现的那种,只要继承源类型,并实现目标接口就行了
- 对象适配器:我们把上例子中的适配器重新实现以下,请看代码
package _13AdapterPattern;
/**
* 对象适配器
*/
public class ObjectAdapterUserInfo implements IUserInfo {
private SourceUserInfo sourceUserInfo;
public ObjectAdapterUserInfo(SourceUserInfo sourceUserInfo)
{
this.sourceUserInfo = sourceUserInfo;
}
@Override
public String getName() {
return sourceUserInfo.getUserInfo("userName");
}
@Override
public String getCompanyAddress() {
return sourceUserInfo.getUserInfo("companyAddress");
}
}
看出来了吧,没错,我们只是把适配器的继承关系改成了组合关系,不过基于“组合优于继承”的原则,大家懂的。