研磨23种大话设计模式------适配器模式

大家好,我是一位在java学习圈中不愿意透露姓名并苟且偷生的小学员,如果文章有错误之处,还望海涵,欢迎多多指正

如果你从本文 get 到有用的干货知识,请帮忙点个赞呗,据说点赞的都拿到了offer

问题引申:

暂时先通过字面理解一下意思,思考一分钟什么意思之后不要再想什么是适配器了,先跟我来看一个例子:
手机打电话用手机卡(以前的手机卡有两种 有个卡套套一张小卡 现在都直接用里面的那张小卡了)支持手机的打电话用流量等等功能(这是普通方法的例子,后面代码中主方法中有测试样例)
那么设计来了,你说你是大卡就是大卡嘛,所以要实现统一的规则(大卡规则接口)
另外手机(老人机)和电话卡(假设现在大家用的都是大卡)之间是什么关系?
很明显是use a的关系,因为生产商生产的手机里面不可能自带电话卡------故排除has a
另外is a理解为手机是一个电话卡或者电话卡是一个手机,很明显更不合理-------故排除is a
那么两者的关系确定了,简单在电话卡中设计两个方法—read—write做个简单的输出即可(这里模拟的仅是一个场景,哈哈方法里面没必要设计的那么高大尚)
上面这个设计很简单吧,难的来咯…
“假设”我的手机现在想安个小卡怎么办?
要不找楼下小黑把我的老人机拿去改装再设计一个接口,能把小卡也插入手机中进行读写操作?
很明显这很麻烦,如果哪天我想读其他种类的卡也给手机开个口?所以综上所述:我们自然而然的想到有没有什么东西能把这个小卡转化成大卡
给小卡加个卡套(这里的卡套就是我们理解的适配器)不就变成大卡了嘛
那么开始设计一个这样的关系吧

适配器模式首先分为三种:对象适配器 类适配器 缺省适配器
下面来将通过上面的例子分别来实现三种方式:
方式一:对象适配器
分析过程:

在理解上面举的例子后,我们知道大卡有很多种类,所以为了让大卡统一规则我们设计一个大卡的接口当规则,同时我们发现想要手机能插入小卡,需要一个卡套(对象适配器),为什么说这个卡套就是对象适配器而不是别的适配器呢?首先注意这个卡套跟小卡的关系(has a)这个关系毋庸置疑吧,就不在赘述了,那么我们先设计一个卡套类,里面放一个小卡对象当属性,那么此时这个小卡与卡套组成的整体就是拥有了小卡的所有功能;
另外注意一下我们的手机是只能放大卡的,那么虽然卡套和小卡组成整体,但这个整体对手机而言也放不进去,想要让整体变大卡,整体是一个大卡怎么表示(在类和类的关系中用is a来表示),那么我们把这个整体实现大卡的规则implements,此时这个整体就是大卡(做个比喻,相当于手机给了这个整体一张大卡通行证)
是不是很简单鸭,下来实现相关代码吧:

手机类的实现代码如下:
package adapter;

/**
 * 手机类
 */
public class Phone {

    //设计一个方法读和写电话卡的数据
    //注意理解这个方法的设计为什么传一个大卡规则的接口
    //因为这个手机只能放大卡,这样的设计才有意义,另外生活中类似的例子很多
    public void readAndWriteCard(BigCard card){
        System.out.println("手机在操作电话卡");
        //本来缺省适配器需要调用同一个方法(即方法名相同内容不同) 这里不再演示
        card.readBigCard();
        card.writeBigCard();
    }

}
移动大卡类的实现代码如:
package adapter;

/**
 * 这是移动的大卡类
 * 如果有其他的大卡种类(比如联通,电信......)实现BigCard这个规则即可
 */
public class PhoneBigCard implements BigCard {

    //设计一个方法读数据
    public void readBigCard(){
        System.out.println("读取大卡");
    }

    //设计一个方法写数据
    public void writeBigCard(){
        System.out.println("写入大卡");
    }
}
大卡规则类的实现代码如下:
package adapter;

public interface BigCard {

    //设计一个方法读数据
    void readBigCard();
    //设计一个方法写数据
    void writeBigCard();
}

移动小卡类的实现代码如下:
package adapter;

/**
 * 移动小卡类
 */
// 先不用在意继承的这个类CompatibilitySmallAndBig,后面会仔细介绍
public class PhoneSmallCard extends CompatibilitySmallAndBig {

    //小卡来挑自己实现兼容器中的哪个方法(这行注释后面会仔细介绍)
    
    // 小卡自己的读写功能
    public void readSmallCard() {
        System.out.println("读取小卡");
    }
    public void writeSmallCard() {
        System.out.println("写入小卡");
    }
}

卡套类的实现代码如下:
package adapter;

/**
 * 卡套类
 * (外表上是大卡的方法接口,但实现部分却是小卡的功能)
 */
public class ConvertSmallToBig implements BigCard {

    //对象适配器
    private PhoneSmallCard smallCard;
    public ConvertSmallToBig(PhoneSmallCard smallCard) {
        this.smallCard = smallCard;
    }

    @Override
    public void readBigCard() {
        smallCard.readSmallCard();
    }

    @Override
    public void writeBigCard() {
        smallCard.writeSmallCard();
    }
}

主方法的实现代码如下:
package adapter;

public class TestAdapter {

    public static void main(String[] args){

        //普通方法的测试样例
//        Phone p = new Phone();
//        PhoneBigCard bc = new PhoneBigCard();
//        p.readAndWriteCard(bc);

        //对象适配器测试样例     理解为小卡套了一个卡套变成了大卡
        //先产生一部手机
        Phone phone = new Phone();
        //产生一张小卡
        PhoneSmallCard smallCard = new PhoneSmallCard();
        //小卡放卡套里组成整体
        BigCard bigCard = new ConvertSmallToBig(smallCard);
        //传给手机照样能用
        phone.readAndWriteCard(bigCard);
    }
}
相信看到这小伙伴们也对对象适配器有了更深刻的理解了,接下来看类适配器又是如何实现的呢…
方式二:类适配器
分析过程:

我们在想能不能不用卡套来实现适配器,让这个手机能装小卡呢,首先再次强调这个手机只能放大卡,所以放小卡不可能做到,那么把小卡变成大卡不就能实现功能了嘛(假设这是一个高科技小卡自动变大变小,当需要装在适合小卡的手机时再变肥来),这种东西未来随着科技进步未尝不可能实现;那么这张智能小卡应该如何设计呢?首先从本质上她还是一张小卡(怎么体现是一张小卡,同理是is a的关系,注意这里的小卡不是规则,我们也并没有设计规则,众多小卡中的一种,暂且叫移动小卡吧,上面代码也有描述),所以首先这个智能小卡要继承移动小卡拥有小卡的功能,其次要实现变大卡还需要实现大卡的规则
那么代码实现如下:

注意对象适配器与类适配器中提到的卡套和智能小卡都是符合或者比较符合(但并不是不合理)现实生活的,所以设计是合理的,不要想当然的设计,要理解面向对象的实质,我个人认为其实面向对象就是面向生活,生活中许多事情都可以用计算机来描述,面向对象就要依据现实生活来合理的设计,而脱离现实生活设计出来的代码或许功能上好用,但一定有它瑕疵的地方,只是我们没注意而已,在代码设计时我们能写出来代码不一定就合理,合理也不一定是最合适最优化的,因此在设计代码之处我们首先就要依据现实生活来思考如何去设计编写一段代码…

智能小卡类的实现代码如下:
package adapter;

/**
 * 智能小卡
 */
//类适配器
public class ClassConvertSmallToBig extends PhoneSmallCard implements BigCard {

    //可以理解为这是一张真实的小卡
    //这张小卡很特殊  特制的小卡    可以变身    可伸缩

    //这两个方法是小卡 伸缩以后的尺寸大小  外观变成了大卡实际上内容是小卡的内容
    @Override
    public void readBigCard() {
        //注意这里的this指调用方法时的那个对象,相当于调用了子类对象调用了从父类那继承过来的方法
        //可能有的人用super会更好理解,但结果都是一样的哦
        this.readSmallCard();
    }

    @Override
    public void writeBigCard() {
        this.writeSmallCard();
    }
}
主方法的实现代码如下:
package adapter;

public class TestAdapter {

    public static void main(String[] args){

        //普通方法的测试样例
//        Phone p = new Phone();
//        PhoneBigCard bc = new PhoneBigCard();
//        p.readAndWriteCard(bc);

        //类适配器测试样例      理解为小卡自己可以变型成大卡
        Phone phone = new Phone();
        BigCard bigCard = new ClassConvertSmallToBig();
        phone.readAndWriteCard(bigCard);
    }
}

最后缺省适配器来了,因为缺省适配器最好理解,所以放最后,但是这里同样来用这个例子就有点不太合理了,但是也简单介绍实现一下,主要理解思想,注释中我还会用文字来描述缺省适配器的,所以小伙伴们放心啦
方式三:缺省适配器
分析过程:

不知道有没有小伙伴知道jdk提供给我们的集合家族List接口和ArrayList和LinkedList(后面两个都是类似于数组能放一堆元素的集合List则是他们两个的规则接口),ArrayList底层是数组,通过数组的创建来实现动态扩容,LinkedList底层是双向链表,底层通过创建新节点来实现动态扩容,假设ArrayList和LinkedList现在都只有add(将元素添加在最后)和ge(获取对应索引的元素)方法,但是两个方法都有一样的代码,于是我们将一样的代码抽取出来形成一个抽象类,让抽象类来实现List接口,ArrayList和LinkedList则来继承抽象类,此时ArrayList和LinkedList就能添加自己独特的属性或者方法了而不用因为实现类List接口而里面的方法都要实现了。
上面这个例子不理解没关系,后面还有两个例子呢,代码如下:

缺省类代码如下:
package adapter;

//缺省适配器   可以理解为这是一个兼容的适配器
public abstract class CompatibilitySmallAndBig implements BigCard{

    //可以理解为这个类是一个兼容器
    //实现了什么规则   就相当于可以读取这种卡片
    //兼容器的方法每一个具体的兼容器都不一样
    //一个类实现了好多不同的接口规则(统一)
    //所有的子类自己挑选自己适合的规则去实现
    //实际上这个例子不适合用来描述缺省适配器,仅做一个扩展
	
	//实际上手机方法中传的只是大卡接口,要实现恰当的缺省适配器,需要手机什么卡都能插,
	//我们在手机方法中传一个卡的总规则(包括小卡和大卡),小卡和大卡功能不一样,
	//自己取挑自己的方法区实现即可,这个代码并不能实现缺省适配器,感兴趣的小伙伴可以去
	//根据刚刚的描述分析自己实现,由于缺省适配器比较简单,这里不再赘述

    //大卡的读写方法
    public void readBigCard(){
        throw new NotFoundOverrideMethodException("Method is null");
    }
    public void writeBigCard(){
        throw new NotFoundOverrideMethodException("Method is null");
    }
    //小卡的读写方法
    public void readSmallCard() {
        throw new NotFoundOverrideMethodException("Method is null");
    }
    public void writeSmallCard() {
        throw new NotFoundOverrideMethodException("Method is null");
    }
}

三种适配器的主方法执行结果如下:
手机在操作电话卡
读取小卡
写入小卡
总结:

举个例子实际开发中我们通过调用一种类(一堆类)的统一方法需要实现接口或继承抽象类来实现多态,但是当其他类不同方法想要去调用时,用于方法名字不一样,所以实现接口已经没用了,这是可以通过适配器来包装我们需要调用的方法,即方法名同名,调用还是一样调,但是方法里的内容已经被换成了此时你想调的那个方法的内容…简而言之:适配器模式主要的作用就是为了将不同的规则转化成统一的 在中间做一个桥梁

对象适配器

设计一个适配器的类 类中包含一个需要转化的对象(将子类包装成目标类)

类适配器

设计一个适配器的类 这个类就是目标类,同时还有子类的特性,这个类实现需要转化目标类的规则同时继承原有类(有点绕,但是结合代码和注释,意思就是实现规则相当于外面包了一层符合规则的皮,继承原有类相当于内容是不符合规则的)–》大概就是平淡的外表,内心却有一个不屈的灵魂

缺省适配器:

这里由于缺省适配器最简单 所以简单描述一下即可,相信小伙伴们可以理解,在实际开发中,一个类如果实现某一个接口,就必须要实现接口中的每一个方法,如果目标接口中的方法太多,而这个类仅仅需要接口中的几个方法,所以中间设计一个缺省适配器-----举个例子:1号缺省适配器实现1号接口重写接口中的所有方法但方法内不做任何实现仅仅抛出自定义异常(也可以不做异常提示,甚至描述成抽象方法即可,但做一个异常提示感觉会更好),1号子类继承1号缺省适配器,重写实现所需的方法即可,但是1号子类若调用了没重写实现的方法就会抛出自定义异常,所以这个异常仅仅做一个提示作用,提示你调方法调错了

看完了小伙伴们是不是对适配器有了更深刻的理解呢?希望这篇文章能帮到小伙伴们更好的理解适配器模式

之后开始慢慢的更新每一种设计模式,通过生动形象的生活现象举例带你感受设计模式的世界,其实设计模式不难,只是当我们面对某个场景时想不到用哪个设计模式该不该用设计模式…
博客内容来自腾讯课堂渡一教育拓哥,以及自己的一些理解认识,同时看了其他大牛写的设计模式技术文章综合总结出来的

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值