美文网首页
设计模式学习笔记:适配器模式-Adapter Pattern

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

作者: 哪吒小子 | 来源:发表于2019-01-07 23:59 被阅读8次

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

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

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

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

    UML图解读

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

    类适配器模型

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

    对象适配器模型

    类适配器

    /**
     * @Description: 目标接口 <br>
     */
    public interface Target {
        //1.operateA是在源(Adaptee)中有实现的
        void operateA();
        //2.operateB在源(Adaptee)中没有实现,需要使用适配器
        void operateB();
    }
    
    /**
     * @Description: 源(Adaptee)角色 <br>
     */
    public class Adaptee {
        public void operateA(){
            System.out.println("我是已经实现的operateA");
        }
    }
    
    /**
     * @Description: 适配器(Adapter)角色 <br>
     */
    public class Adapter extends Adaptee implements Target {
        //其中operateA通过继承的方式已经集成到Adapter中了
        @Override
        public void operateB() {
            System.out.println("我是通过适配器实现的operateB");
        }
    }
    
    /**
     * @Description: 类适配器模式 <br>
     */
    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<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(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<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(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

          本文链接:https://www.haomeiwen.com/subject/mdtmkqtx.html