美文网首页Android开发Java 杂谈Android开发经验谈
学习、探究Java设计模式——适配器模式

学习、探究Java设计模式——适配器模式

作者: 丶蓝天白云梦 | 来源:发表于2019-04-01 16:07 被阅读4次

    前言

    在Android开发中,我们会经常遇到ListAdapter、RecyclerViewAdapter等带有Adapter字样的类,其实这里就用到了适配器模式,由于适配器模式的使用频率极高,因此这篇文章就来探究一下适配器模式及其应用场景。

    定义

    适配器模式,将一个类的接口转换成客户端期望的另一个接口。使得两个没有关联的类能够在适配器的作用下进行合作。

    UML类图

    适配器模式划分为两种形式:类适配器模式和对象适配器模式。
    1、类适配器模式


    类适配器模式

    由类适配器模式的UML类图,我们可以知道Adaptee是被适配对象,而Target是目标接口,Adapter则是适配器,我们要实现的是让Adaptee具有Target接口,即“转换接口”,客户端能通过Adaptee使用Target功能。在类适配器模式下,这是通过让Adapter继承Adaptee并实现Target接口来实现的(Java不支持多继承,因此只能实现某一接口)。

    2、对象适配器模式


    对象适配器模式

    对象适配器模式的UML类图与类的相似,不同之处在于Adapter与Adaptee的关系不再是继承关系,而是组合关系,Adapter通过持有Adaptee的一个引用并实现Target接口来实现适配器模式。

    实现

    1、类适配器模式

    首先对于一个被适配器,它的代码如下,它有自己特有的方法,但这不是客户端所期望的。

    public class Adaptee {
        
        public void specificRequest(){
            System.out.println("Adaptee 特有的方法");
        }
    }
    

    客户端所期望的是Adaptee有另外一个功能,即下面Target接口所提供的方法:

    public interface Target {
    
        //客户端所期望的接口方法
        void request();
    }
    

    也就是说,对于一个具体的Adaptee,我们期望它拥有一个它没有的方法,以达到我们的期望,也即是“接口转换”,下面就是适配器Adapter,它继承自Adaptee,实现了Target接口:

    public class Adapter extends Adaptee implements Target {
    
        @Override
        public void specificRequest() {
            super.specificRequest();
        }
    
        @Override
        public void request() {
            System.out.println("Adaptee 拥有了Target接口的方法,达到了用户的预期");    
        }
    }
    

    2、对象适配器模式

    对象适配器模式中,Target接口和Adaptee类与上述代码相同,不同之处在于Adapter不是继承Adaptee,而是用一个成员变量去引用它,代码如下:

    public class Adapter  implements Target {
    
        private Adaptee mAdaptee;
        
        public Adapter(Adaptee adaptee){
            mAdaptee = adaptee;
        }
    
        @Override
        public void request() {
            //接口转换的一系列工作,利用mAdaotee的方法、变量等去实现具体需求
            //调用mAdapter.specificRequest()...等
            System.out.println("Adaptee 拥有了Target接口的方法,达到了用户的预期");
        }
    }
    

    举个例子

    在日常生活中,与适配器模式有关的最常见的例子就是电压的转换。我们知道,通过电网提供给每个家庭的电压是交流电压220V,但是我们给手机、笔记本电脑充电的时候,并不能直接接在220V交流电上,而是需要通过电源适配器来把交流电转换成直流电,并输出较低的电压来使用。这里的电源适配器其实就是用到了适配器模式,比如苹果手机电源适配器的常用输出是5V/1A,这就是经过转换后的电压,这样才能安全地给用电器充电。下面我们就用代码来模拟这一效果。
    (1)先看被适配者adaptee,也即是电网提供的AC 220V:

    public class PowerGrid {
    
        /**
         * 电网能够直接为我们提供220V AC电压
         * @return
         */
        public int outPutAC220V(){
            return 220;
        }
    }
    

    (2)下面就是Target接口,也即是客户端所期望电网通过某些转换能够提供的功能:

    public interface VoltageConversion {
    
        //客户端期望适配器为我们提供5V和20V的直流电
        int outPutDC5V();
        int outPutDC20V();
    }
    

    (3)接着就是电源适配器了,它实现了Target接口,对外提供了5V和20V的直流电压输出,它内部实现了电网提供的220V交流电的转换:

    public class VoltageAdapter implements VoltageConversion {
    
        private PowerGrid mPowerGrid;
    
        public VoltageAdapter(PowerGrid adaptee){
            mPowerGrid = adaptee;
        }
    
        /**
         *  如果有需求,适配器需要输出原来电网能提供的电压
         */
        public int outPutAC220V(){
            return mPowerGrid.outPutAC220V();
        }
    
        @Override
        public int outPutDC5V() {
            int voltageFromPowerGrid = mPowerGrid.outPutAC220V();
            System.out.printf("电源适配器正在工作,将%dV交流电转换成5V直流电...\n",voltageFromPowerGrid);
            return 5;
        }
    
        @Override
        public int outPutDC20V() {
            int voltageFromPowerGrid = mPowerGrid.outPutAC220V();
            System.out.printf("电源适配器正在工作,将%dV交流电转换成20V直流电...\n",voltageFromPowerGrid);
            return 20;
        }
    }
    

    (4)最后,我们写一个Test测试类,来测试我们的代码:

    public class AdapterTest {
    
        public static void main(String args[]){
            PowerGrid powerGrid = new PowerGrid();
            VoltageAdapter adapter = new VoltageAdapter(powerGrid);
    
            //首先,我们用适配器给苹果手机充电
            System.out.println("给苹果手机充电,适配器提供的电压为:" + adapter.outPutDC5V());
    
            //接着,我们用适配器给支持快充的手机充电
            System.out.println("给支持QC4.0的手机充电,适配器提供的电压为:" + adapter.outPutDC20V());
        }
    }
    

    运行结果如下图所示:


    运行结果

    可以看出,适配器输出了我们想要的5V和20V,它内部对220V交流电压进行电压变换,也即是“接口转换”,把原本不具备的功能兼容到客户所需求的功能上了。

    适配器模式和装饰者模式的比较

    学习完适配器模式后,读者可能会觉得适配器模式和之前学习过的装饰者模式有很多相似之处,因为它们都持有了一个对象的引用(包装该对象),并且让这个对象做出了这个对象原本没有的行为。那它们之间的区别在哪呢?答案是:适配器模式将一个对象包装起来以改变其接口;而装饰者模式将一个对象包装起来以增加新的行为和责任。
    笔者认为,二者的突出的重点不同,适配器模式主要是为了改变接口,也即是被适配对象原本就有一个方法,但不适合客户端使用,为了让客户端可以兼容使用到该方法,就利用了适配器把这个方法进行接口转换,让客户可以使用。那上面的电压转换的例子来说,就是电网本来就提供了一个220V的电压输出,只不过这不符合我们的需求,所以将它转换成5V,即是进行了所谓的接口转换。但装饰者模式,是提供被包装对象所没有的方法,比如装饰者包装一个电网,它除了能提供220V输出之外,还能提供计算电费的功能,即是增加了新的行为和责任

    好了,这篇文章到这里就结束了。本文主要介绍了适配器模式的概念以及实现方法和具体的例子,最后与装饰者模式做了比较,希望各位同学能从中获益。如果可以的话,希望能给我点个赞,谢谢~

    相关文章

      网友评论

        本文标题:学习、探究Java设计模式——适配器模式

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