Java设计模式学习记录-适配器模式

前言

之前已经将五个创建型设计模式介绍完了,从这一篇开始介绍结构型设计模式,适配器模式就是结构型模式的一种,适配器要实现的效果是把“源”过渡到“目标”。

适配器模式

在开发过程中,使用一个已经存在的类,而他的接口不符合我们的需求。这个时候我们本着开闭原则,要创建一个既符合我们需求又实现了已存在的接口的类,这个类可以把其他不相关或不可预见的类协同起来一起工作。我们创建的这个类就是适配器类,起到了一个转换的作用。

适配器模式有类型的适配器模式和对象适配器模式两种实现方式

面向类的适配器模式

面向类的适配器实现起来并不复杂,主要的思想就是靠继承来实现适配。举个?,如果我们在调用一个接口的时候,发现这个接口中没有能实现我们需求的方法,然后发现这个接口旁边的一个类中有我们想要的方法,这个时候我们就可以创建一个适配器类,来继承接口旁边的这个类,并实现调用接口。这样就满足了我们既没有改变调用方式又实现了功能需求。

如下代码功能:

定义一个数据线接口

public interface IMobilePhone {
    /**
     * 谷歌数据线
     * @return
     */
    String google();

    /**
     * 苹果数据线
     * @return
     */
    String apple();
}

当我们调用数据线接口时发现没有type-c类型接口的数据线,然后发现了下面的这个类里有。

public class HuaWei {
    /**
     * 华为的type-c数据线
     * @return
     */
    public String huawei(){
        return "huawei:type-C";
    }

}

然后我们就创建一个适配器类来满足我们的需求。

public class Adapter extends HuaWei implements IMobilePhone {
    @Override
    public String google() {
        return "Android:数据线";
    }

    @Override
    public String apple() {
        return "IOS:数据线";
    }
}

使用方式如下:

public class AdapterTest {

    public static void main(String[] args) {

        HuaWei dataLine = new Adapter();

        String typC = dataLine.huawei();

        System.out.println(typC);

    }

}

运行结果:

huawei:type-C

在上面的例子中,我们通过Adapter类继承自HuaWei类,然后实现了IMobilePhone接口,做到了适配的效果,但是这种适配器是有明确规定了父类的。由于Java语言的特性,类只能单继承,决定了这个适配器只能用在这个业务当中。如果我们又需要另一个类里面的方法呢?这个时候就又需要创建一个子类来实现适配,这也是为什么这种方式叫类适配器的原因。

面向对象适配器模式

为了解决类适配器只是适配单一类的这个问题,就又出现了对象适配器模式,对象适配器,是将适合类的对象注入到适配器中,然后达到适配的作用。

其他的代码没有变化,只需要更改适配器类。

更改后如下所示:

public class Adapter implements IMobilePhone {
    @Override
    public String google() {
        return "Android:数据线";
    }

    @Override
    public String apple() {
        return "IOS:数据线";
    }

    public Adapter(){}

    private HuaWei huaWei;

    public Adapter(HuaWei huaWei){
        this.huaWei = huaWei;
    }

    public String huawei(){
        return huaWei.huawei();
    }

}

适配器类,不再继承HuaWei类,而是通过构造函数将HuaWei类的对象注入进来,然后定义一个方法来调用要使用的方法。

测试如下:

public class AdapterTest {

    public static void main(String[] args) {

        HuaWei huaWei = new HuaWei();

        Adapter dataLine = new Adapter(huaWei);

        String typC = dataLine.huawei();

        System.out.println(typC);

    }

}

运行结果:

huawei:type-C

对象适配器模式,可以为多个类进行适配(多个构造方法),解决了类适配模式的单一化问题。

但是其实除了对象适配器模式和类适配器模式,还有一种方式也是实现适配的方法,接口适配器模式。当我们想实现一个接口,但又不想实现所有接口方法,而只想去实现一部分方法时,就可以使用接口适配器。它的做法是在接口和具体实现类中添加一个抽象类,而用这个抽象类去实现目标接口的所有方法。而具体的实现类只需要覆盖其需要完成的方法即可。

例如有如下接口:

public interface MobilePhoneBrand {

    String xiaomi();
    String huawei();
    String apple();
    String vivo();
    String oppo();
    String samsung();
}

对应的抽象类如下:

public abstract class MobilePhoneDefault implements MobilePhoneBrand{

    public String xiaomi(){
        return null;
    }
    public String huawei(){
        return null;
    }
    public String apple(){
        return null;
    }
    public String vivo(){
        return null;
    }
    public String oppo(){
        return null;
    }
    public String samsung(){
        return null;
    }

}

实现类中我只想使用中国品牌的手机,所以只需实现部分方法就可以了。

public class ChinaMobilePhone extends MobilePhoneDefault {

    public String xiaomi(){
        return "小米";
    }

    public String huawei(){
        return "华为";
    }

    public String vivo(){
        return "VIVO";
    }

    public String oppo(){
        return "OPPO";
    }

}

适配器模式的3个实现方式介绍完了,下面来说说适配器模式的结构,如下图:

 适配器模式中有如下4个角色:

目标抽象角色(Target):定义客户所期待要使用的接口,在第一个例子中的IMobilePhone就是代表的这个角色。

源角色(Adaptee):也叫被适配角色,在第一例子中HuaWei代表的就是这个角色。

适配器角色(Adapter):用来把源角色转换成符合要求的目标接口设备,在第一个例子中Adapter类代表的就是这个角色。

客户端(Client):这个就是具体使用角色,在第一个例子中的AdapterTest代表的就是这个角色。

想了解更多的设计模式请查看Java设计模式学习记录-GoF设计模式概述

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏.NET技术

简单工厂模式和策略模式的区别与结合

    简单工厂模式和策略模式是大部分程序员,在学习设计模式时接触得最早,或在工作实践中也是用得相对比较多的两个设计模式。

8045
来自专栏Golang语言社区

十条有用的 Golang语言 技术

十条有用的 Go 技术 这里是我过去几年中编写的大量 Go 代码的经验总结而来的自己的最佳实践。我相信它们具有弹性的。这里的弹性是指: 某个应用需要适配一个灵...

3726
来自专栏AndroidTv

Exception 和 Error 有什么区别么声明提问正文

1555
来自专栏Golang语言社区

十条有用的 Golang语言 技术

十条有用的 Go 技术 这里是我过去几年中编写的大量 Go 代码的经验总结而来的自己的最佳实践。我相信它们具有弹性的。这里的弹性是指: 某个应用需要适配一个灵...

4159
来自专栏原创

教你如何用AST语法树对代码“动手脚”

作为程序猿,每天都在写代码,但是有没有想过通过代码对写好的代码”动点手脚”呢?今天就与大家分享——如何通过用AST语法树改写Java代码。 先抛一个问题:如何将...

6056
来自专栏chenssy

【死磕Java并发】—–J.U.C之并发工具类:Exchanger

前面三篇博客分别介绍了CyclicBarrier、CountDownLatch、Semaphore,现在介绍并发工具类中的最后一个Exchange。Exchan...

3296
来自专栏我就是马云飞

从架构角度看Retrofit的作用、原理和启示

前言 Retrofit是squareup公司的开源力作,和同属squareup公司开源的OkHttp,一个负责网络调度,一个负责网络执行,为Android开发者...

51110
来自专栏ImportSource

设计模式-抽象类,只是想为你做更多

如果说面向对象中的接口是把所有的事情扔给你的话,那么抽象类显然是想要为你做一些事情,如果实在有一部分做不了再扔给你。 相信对于大部分业务开发的场景下都不太会需要...

3557
来自专栏PhpZendo

PHP 多任务协程处理

上周 有幸和同事一起在 SilverStripe 分享最近的工作事宜。今天我计划分享 PHP 异步编程,不过由于上周我聊过 ReactPHP;我决定讨论一些不一...

1281
来自专栏网络

编码在网络安全中的应用和原理

前言:现在的网站架构复杂,大多都有多个应用互相配合,不同应用之间往往需要数据交互,应用之间的编码不统一,编码自身的特性等都很有可能会被利用来绕过或配合一些策略,...

3006

扫码关注云+社区

领取腾讯云代金券