结构型模式
组成
在某些场景下,我们想复用一个已有的类,但是该类与我们要使用它的场景中其他类不兼容,这个时候,我们可以使用Adapter 模式。
Adapter 模式有两种实现方式:类继承、对象组合,UML 如下所示:
图1. 类适配器使用多重继承对两个(接口)进行匹配
图2. 对象适配器依赖于对象组合
Adapter 模式一般由以下组成:
1、Client--客户端,调用 Target 对象
2、Target--提供方法,与 Client 进行协同
3、Adaptee-- 已经存在的类,想复用的对象类
4、Adapter-- 对Adaptee与Tagrget进行适配
Client 直接调用的是 Target 类,但是我们想调用的是 Adaptee 的方法,这个时候,我们就需要对Target进行适配。因为Target是无法修改的,所以我们只能让Adapter继承或实现Target类,然后在Adapter类中把请求转发给Adaptee的方法。
在图1中,Adapter 继承了 Target类,并实现了Adaptee接口,然后在 Adapter 的方法(request 方法继承自 Target)中调用继承自 Adaptee 的方法。
在图2中,Adapter继承了Target类,但是持有了Adaptee对象的引用,然后在Target的方法中调用了Adaptee 对象的方法。
选择权衡
类适配器
- Adapter 类继承了 Adaptee 类,当想要适配 Adaptee 的其他子类时,无法实现
- 仅仅引入一个对象,不需要额外的对 Adaptee 的引用
对象适配器:
- 允许 Adapter 与 Adaptee 的任意子类适配
- 需要额外一个对 Adaptee 对象的引用
变和不变
不变的是Client 和 Target,Client 永远是调用Target去实现逻辑;
变化的是“Adaptee”,Target可以引用不同的Adaptee 来具体实现Client 的请求;
为了适配 Target和Adaptee,需要一个 Adapter。
应用场景
一个已经存在的类(Target),我们想复用它,但是它不满足我们的要求,我们又没办法修改它,这个时候我们可以使用适配器模式从中产生我们需要的类(Adaptee)。
示例代码
在 Spring Session 框架中,就使用了 Adapter模式,比如 HttpSessionAdapter类作为 HttpSession 和 Session 的适配器,类的定义如下:
class HttpSessionAdapter<S extends Session> implements HttpSession {
private static final Log logger = LogFactory.getLog(HttpSessionAdapter.class);
private S session;
private final ServletContext servletContext;
private boolean invalidated;
private boolean old;
HttpSessionAdapter(S session, ServletContext servletContext) {
if (session == null) {
throw new IllegalArgumentException("session cannot be null");
}
if (servletContext == null) {
throw new IllegalArgumentException("servletContext cannot be null");
}
this.session = session;
this.servletContext = servletContext;
}
}
Spring session 想复用已有的 HttpSession 对象,且已有的 HttpSession 对象不满足需求(比如定时过期等),Spring session 就创建了满足自己需求的接口 Session,然后把两者适配起来:
1、使用HttpSessionAdapter来适配这两个接口:HttpSessionAdapter实现了HttpSession,然后持有一个Session实例
2、把HttpSessionAdapter作为HttpSession实例注入到容器中
3、每次调用HttpSession相关方法时,HttpSessionAdapter实际调用的是Session的方法
优点和缺点
小结
感觉适配器模式更多的场景是:我们依赖了一个框架(外部环境),框架中的类 X 不满足我们的要求,我们可以通过继承这个类来重写它的某些方法,也可以自定义 Adaptee 然后用 Adapter 来适配 X 和 Adaptee。