zoukankan      html  css  js  c++  java
  • 003-结构型-01-适配器模式(Adapter)

    一、概述

      将一个类的接口转换成客户期望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。

      让原来不兼容的两个接口协同工作

    1.1、适用场景

      已经存在的类,它的方法和需求不匹配时(方法结果相同或相似)

      不是软件设计阶段考虑的设计模式,是随着软件维护。由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案

      类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。

      对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。

      接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。

    1.2、优缺点

    优点:

    • 能提高类的透明性和复用,现有的类复用但不需要改变
    • 目标类和适配器类解耦,提高程序扩展性
    • 符合开闭原则

    缺点:

    • 适配器编写过程需要全面考虑,可能会增加系统的复杂性
    • 增加系统代码可读的难度

    1.3、类图角色及其职责

    适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。

    1.3.1、类适配:创建新类,继承原类,并实现新接口,例如 

        

        原本设计应该是多重继承,java不能多重继承,上述是接口Target

        让Adapter继承Adaptee类,Client在使用Target的request()接口(实际上是调用Adapter的request()方法)时,间接调用adapteeRequest()方法。

    class Adaptee{
        void adapteeRequest(){
            System.out.println("com.github.bjlhx15.patterns.base.structure.adapter.Adaptee.adapteeRequest");
        }
    }
    interface Target{
        void request();
    }
    
    public class Adapter extends Adaptee implements Target{
    
        @Override
        public void request() {
            System.out.println("com.github.bjlhx15.patterns.base.structure.adapter.Adapter.request");
            this.adapteeRequest();
        }
    }

      测试

        @Test
        public void request() {
            Target target = new Adapter();
            target.request();
        } 

      上述类图

        

    1.3.2、对象适配:创建新类持源类的实例,并实现新接口,例如 

      

      使用组合

      对比着类适配器理解。在Adapter内部创建Adaptee对象,Client在使用Target的request()接口(实际上是调用Adapter的request()方法)时,间接调用adapteeRequest()方法。

    class Adaptee2{
        void adapteeRequest2(){
            System.out.println("com.github.bjlhx15.patterns.base.structure.adapter.Adaptere2.adapteeRequest2");
        }
    }
    
    interface Target2{
        void request();
    }
    
    public class Adapter2 implements Target2 {
        private Adaptee2 adaptee2;
    
        public Adapter2(Adaptee2 adaptee2) {
            this.adaptee2 = adaptee2;
        }
        @Override
        public void request() {
            System.out.println("com.github.bjlhx15.patterns.base.structure.adapter.Adapter2.request");
            adaptee2.adapteeRequest2();
        }
    }

    测试

        @Test
        public void request() {
            Target2 target2 = new Adapter2(new Adaptee2());
            target2.request();
        }

    上述类图

      

    适配器模式包含一下三个角色:

    • Target(目标抽象类):目标抽象类定义客户所需的接口,可以是一个抽象类或接口,也可以是具体类。在类适配器中,由于Java语言不支持多重继承,所以它很可能是接口。

    • Adapter(适配器类):它可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配。它是适配器模式的核心。

    • Adaptee(被适配类):被适配类即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类包好了客户希望的业务方法。

    1.3.3、接口的适配器模式

      有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。

      

    1.4、演进过程

    1.5、类适配与对象适配区别

    1、对象适配器通过委派与adaptee衔接,即持有adaptee对象,是动态的方式;类适配器通过集成与adaptee衔接,也就是说类适配器继承adaptee,并且实现target方法,是静态的方式。

    2、由于对象适配器采用动态的方式与adaptee衔接,使得它可以对不同的适配源及其子类进行适配

    3、类适配器可以重定义实现行为,而对象适配器重定义适配的行为比较困难,但是添加行为较方便。

    尽量使用对象适配器的实现方式,多用合成/聚合、少用继承。



    作者:强布斯
    链接:https://www.jianshu.com/p/6f5a7d6858e7
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    二、扩展

    扩展-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

    2.1、分析org.springframework.web.servlet.HandlerAdapter

    类图

      

    2.1、分析org.springframework.web.servlet.mvc.Controller

    类图

      

  • 相关阅读:
    project euler 开坑
    hdu 5382 GCD?LCM!
    Leetcode 557. 反转字符串中的单词 III
    Leetcode 344. 反转字符串
    Leetcode 345. 反转字符串中的元音字母
    008.C++类改写模板类
    007.C++构造函数
    006.C++头文件
    02.树的序列化与反序列化(C++)
    Leetcode 94. 二叉树的中序遍历
  • 原文地址:https://www.cnblogs.com/bjlhx/p/11193799.html
Copyright © 2011-2022 走看看