设计模式学习笔记:适配器模式-Adapter Pattern

适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。

  • 我的技术博客:https://nezha.github.io,https://nezhaxiaozi.coding.me
  • 我的地址:https://www.jianshu.com/u/a5153fbb0434
  • 本文的demo地址:DesignPatterns/AdapterPattern

适配器模式主要有两种模式:1.类适配器模式2.对象适配器模式

其中:类适配器模式主要使用的是继承的思想;对象适配器模式使用的组合引用的思想。
不管哪种模式下,适配者模式的主要组成部分有三部分:

  1. 目标(Target)角色:这就是所期待得到的接口。注意,由于这里讨论的是类适配器模式,因此目标不可以是类。
  2. 源(Adaptee)角色:有目标(Target)角色的部分功能,但是还是不满足或者是源(Adaptee)直接不满足目标的接口功能,需要配置它。
  3. 适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一叫色不可以是接口,而必须是具体类。

UML图解读

下图是类适配器的UML图,其中Target是目标接口,含有两个待实现的方法;Adaptee是源接口(需要被改造或者扩展),它有一个实现方法operateA;然后适配器AdapterimplementsTarget接口,并且集成了Adaptee源接口。所以通过适配器类就可以有完整的Target接口功能了。最后在客户端使用中就可以将Target接口的实例化指向Adapter类了。

设计模式学习笔记:适配器模式-Adapter Pattern_第1张图片
类适配器模型

还有一种比较常见的适配器就是对象适配器了。Target接口和Adaptee源接口都没有变化;最大的变化还是适配器类了,首先Adapter类放弃使用继承而是使用引用的方式来引入源接口,然后Adaptee的实例对象也是通过构造方法延迟注入了;最后还是需要实现Target接口的两个方法,只不过operateA是通过Adaptee源的实例对象执行的。

设计模式学习笔记:适配器模式-Adapter Pattern_第2张图片
对象适配器模型

类适配器

/**
 * @Description: 目标接口 
*/ public interface Target { //1.operateA是在源(Adaptee)中有实现的 void operateA(); //2.operateB在源(Adaptee)中没有实现,需要使用适配器 void operateB(); } /** * @Description: 源(Adaptee)角色
*/ public class Adaptee { public void operateA(){ System.out.println("我是已经实现的operateA"); } } /** * @Description: 适配器(Adapter)角色
*/ public class Adapter extends Adaptee implements Target { //其中operateA通过继承的方式已经集成到Adapter中了 @Override public void operateB() { System.out.println("我是通过适配器实现的operateB"); } } /** * @Description: 类适配器模式
*/ public class AdapterClient { public static void main(String[] args) { //目标Target是通过适配器Adapter获得的 Target adapter = new Adapter(); adapter.operateA(); adapter.operateB(); } } 结果: 我是已经实现的operateA 我是通过适配器实现的operateB

对象适配器

public interface Target {
    //1.operateA是在源(Adaptee)中有实现的
    void operateA();
    //2.operateB在源(Adaptee)中没有实现,需要使用适配器
    void operateB();
}

public class Adaptee {
    public void operateA(){
        System.out.println("在源(Adaptee)中实现的operateA");
    }
}

public class Adapter implements Target {

    private Adaptee adaptee;

    public Adapter(Adaptee adaptee){
        this.adaptee = adaptee;
    }

    @Override
    public void operateA() {
        //通过传入的源对象实现operateA
        this.adaptee.operateA();
    }

    @Override
    public void operateB() {
        System.out.println("我是通过适配器的实现接口实现的operateB");
    }
}

public class AdapterClient {
    public static void main(String[] args) {
        //1.实例化源 Adaptee
        Adaptee adaptee = new Adaptee();
        //2.创建适配者对象,并且传入源
        Target target = new Adapter(adaptee);
        target.operateA();
        target.operateB();
    }
}

结果:
在源(Adaptee)中实现的operateA
我是通过适配器的实现接口实现的operateB

应用场景

Spring 中也有适配器模式的典型应用。

SpringAOP 中,使用的 Advice (通知)来增强被代理类的功能。Spring 实现这一 AOP 功能的原理就使用代理模式(1、JDK动态代理。2、CGLib字节码生成技术代理。)对类进行方法级别的切面增强,即,生成被代理类的代理类, 并在代理类的方法前,设置拦截器,通过执行拦截器的内容增强了代理方法的功能,实现的面向切面编程。

Advice(通知)的类型有:MethodBeforeAdviceAfterReturningAdviceThrowsAdvice的。

在每个类型Advice(通知)都有对应的拦截器,MethodBeforeAdviceInterceptorAfterReturningAdviceInterceptorThrowsAdviceInterceptor

Spring 需要将每个Advice(通知)都封装成对应的拦截器类型,返回给容器,所以需要使用适配器模式对Advice进行转换。下面我们看看具体的代码。

MethodBeforeAdvice类:Adaptee

Adapter类接口:Target

MethodBeforeAdviceAdapter类,Adapter

DefaultAdvisorAdapterRegistry类,Client

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
 
    private final List adapters = new ArrayList(3);
 
 
    /**
     * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
     */
    public DefaultAdvisorAdapterRegistry() {//这里注册了适配器
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }
 
 
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        if (adviceObject instanceof Advisor) {
            return (Advisor) adviceObject;
        }
        if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;
        if (advice instanceof MethodInterceptor) {
            // So well-known it doesn't even need an adapter.
            return new DefaultPointcutAdvisor(advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            // Check that it is supported.
            if (adapter.supportsAdvice(advice)) {//这里调用了适配器的方法
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new UnknownAdviceTypeException(advice);
    }
 
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List interceptors = new ArrayList(3);
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {//这里调用了适配器的方法
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
    }
 
    public void registerAdvisorAdapter(AdvisorAdapter adapter) {
        this.adapters.add(adapter);
    }
 
}

参考文献

  1. 设计模式干货系列:(七)适配器模式【学习难度:★★☆☆☆,使用频率:★★★★☆】
  2. Spring中的设计模式-适配器模式
  3. 设计模式(二) 三种适配器模式 总结和使用场景

你可能感兴趣的:(设计模式学习笔记:适配器模式-Adapter Pattern)