该项目源码地址:https://github.com/ggb2312/Code/tree/master/java-basic/design-pattern
(设计模式相关代码与笔记)
1. 定义
将一个类的接口转换成客户期望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。
2. 适用场景
- 已经存在的类,它的方法和需求不匹配时(方法结果相同或相似)
- 不是软件设计阶段考虑的设计模式,是随着软件维护。由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案
3. 适配器类图与角色
3.1 适配器类型
适配器类型有两种类型实现,一种是类适配器,一种是对象适配器。
(1)类适配器
通过类继承实现的。
让Adapter继承Adaptee类,Client在使用Target的request()接口(实际上是调用Adapter的request()方法)时,间接调用adapteeRequest()方法。
(2)对象适配器
符合组合复用原则,使用委托机制。
对比着类适配器理解。在Adapter内部创建Adaptee对象,Client在使用Target的request()接口(实际上是调用Adapter的request()方法)时,间接调用adapteeRequest()方法。
3.2 角色
由图可知适配器模式包含一下三个角色:
Target(目标抽象类):目标抽象类定义客户所需的接口,可以是一个抽象类或接口,也可以是具体类。在类适配器中,由于Java语言不支持多重继承,所以它很可能是接口。
Adapter(适配器类):它可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配。它是适配器模式的核心。
Adaptee(被适配类):被适配类即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类包好了客户希望的业务方法。
4. 相关设计模式
适配器模式和外观模式
- 适配器复用现有的接口,外观模式则是定义新的接口。
5. 模式实例
5.1 类适配器
Adaptee 有一个被适配器类:
public class Adaptee {
public void adapteeRequest() {
System.out.println("被适配者的方法");
}
}
Target 这个是目标方法的接口:
public interface Target {
void request();
}
ConcreteTarget 这个是目标方法的实现:
/** 具体的实现类 */
public class ConcreteTarget implements Target {
@Override
public void request() {
System.out.println("ConcreteTarget目标方法");
}
}
Adapter 而这个就是适配类:继承于被适配类,实现目标方法的接口:
public class Adapter extends Adaptee implements Target {
@Override
public void request() {
super.adapteeRequest();
}
}
Client 我们来进行测试一下:
public class Test {
public static void main(String[]args){
Target target = new ConcreteTarget();
target.request();
/** 现在,我们就来通过适配器类来进行实现 */
Target adapterTarget = new Adapter();
adapterTarget.request();
}
}
测试结果:
此时的类图:
5.2 对象适配器
有一个目标接口:
public interface Target {
void request();
}
有一个具体的目标类:
/** 具体的实现类 */
public class ConcreteTarget implements Target {
@Override
public void request() {
System.out.println("ConcreteTarget目标方法");
}
}
以及被适配的类:
public class Adaptee {
public void adapteeRequest() {
System.out.println("被适配者的方法");
}
}
适配类和上面的有一些不同,这里被适配类不是继承过来的,而是作为属性组合到里面来,然后通过对象来调用被适配类里面的方法:
public class Adapter implements Target {
private Adaptee adaptee = new Adaptee();
@Override
public void request() {
adaptee.adapteeRequest();
}
}
测试:
public class Test {
public static void main(String[]args){
Target target = new ConcreteTarget();
target.request();
/** 现在,我们就来通过适配器类来进行实现 */
Target adapterTarget = new Adapter();
adapterTarget.request();
}
}
测试结果:
此时类图:
5.3 适配器demo
简单的抽象一个场景:手机充电需要将220V的交流电转化为手机锂电池需要的5V直流电,我们的demo就是写一个电源适配器,将 AC220v ——> DC5V
首先有一个被适配的类:220V的类
public class AC220 {
public int outputAC220V() {
int output = 220;
System.out.println("输出220V的交流电"+output+"V");
return output;
}
}
我们有一个目标方法的接口:转为5V的直流电
public interface DC5 {
int outputDC5V();
}
这个就是适配类(使用对象适配):
public class PowerAdapter implements DC5 {
private AC220 ac220 = new AC220();
@Override
public int outputDC5V() {
int adapterInput = ac220.outputAC220V();
/** 变压器 */
int adapterOutput = adapterInput / 44;
System.out.println("通过PowerAdapter电源适配器输入AC"+adapterInput+"V"+"输出DC:"+adapterOutput+"V");
return adapterOutput;
}
}
测试:
public class Test {
public static void main(String[]args){
DC5 dc5 = new PowerAdapter();
dc5.outputDC5V();
}
}
测试结果:
6. 优缺点
优点:
- 能提高类的透明性和复用,现有的类复用但不需要改变
- 目标类和适配器类解耦,提高程序扩展性
- 符合开闭原则
缺点:
- 适配器编写过程需要全面考虑,可能会增加系统的复杂性
- 增加系统代码可读的难度
7. 扩展-JDK1.7以及框架源码中的适配器模式
javax.xml.bind.annotation.adapters.XmlAdapter
org.springframework.aop.framework.adapter.AdvisorAdapter、MethodBeforeAdviceAdapter
org.springframework.orm.jpa.JpaVendorAdapter
org.springframework.web.servlet.HandlerAdapter、org.springframework.web.servlet.DispatcherServlet、org.springframework.web.servlet.mvc.Controller