【设计模式In Java】五、适配器模式

适配器模式

定义

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

在适配器模式定义中所提及的接口是指广义的接口,它可以表示一个方法或者方法的集合。

在适配器模式中,我们通过增加一个新的适配器类来解决接口不兼容的问题,使得原本没有任何关系的类可以协同工作。根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。

在对象适配器的使用过程中,如果在适配器中同时包含对目标类和适配者类的引用,适配者可以通过它调用目标类中的方法,目标类也可以通过它调用适配者类中的方法,那么该适配器就是一个双向适配器。

场景

在开发当中,特别是在面向接口编程的过程中,已经定义好了一些接口,并且这些接口已经被声明使用,根据依赖倒转原则,面向接口编程是依赖于接口或抽象类的,这些接口和接口的方法一旦声明和使用,几乎不能修改。但不巧的是,接口中的方法已经在另一个接口或另一个类方法中实现,或者说想在接口中复用另一个方法,那么就可以使用适配器模式。

假设现在已经提供了USB接口,但是华为手机使用的是Type-C接口充电,iPhone使用的是Lightning接口充电,如何使用这个USB接口为两种不同接口的手机充电呢?因为充电的功能已经在USB接口提供,苹果和华为的充电接口已经制定不能修改,所有充电设备都必须基于各自的接口开发,所以我们必须开发有两种接口的USB充电线——即一个USB接口适配器,可以为两种手机充电。

代码

adapter

对象适配器模式

在这里插入图片描述
示例:

public class TestAdapter {

    @Test
    public void test(){
        Usb usb = new UsbAdapter();
        usb.chargeLightning();
        usb.chargeTypeC();
    }
    /*
     Connected to Iphone Lightning interface...
     Connected to Huawei Type-C interface...
     */
}

类适配器模式

类适配器模式和对象适配器模式最大的区别在于适配器和适配者之间的关系不同,对象适配器模式中适配器和适配者之间是关联关系,而类适配器模式中适配器和适配者是继承关系。
在这里插入图片描述

public class TestAdapter {

    @Test
    public void test(){
        Usb usbLightningAdapter = new UsbLightningAdapter();
        Usb usbTypeCAdapter = new UsbTypeCAdapter();

        usbLightningAdapter.chargePhone();
        usbTypeCAdapter.chargePhone();
    }

}

从UML图看起来类适配器模式更加形象,因为类适配器模式真正地起到了桥梁模式,但是这样的适配有局限性:由于Java不能多继承,如果想要同时适配多个适配者,是很难达到目标的,而且如果适配者和适配目标需要适配的方法名称相同,也会有问题。

双向适配器

还是上面的两种适配器都是单向的,目标是为了构造一个能为手机充电的USB设备。但现在有一种情况:USB接口已经开发完成,集成在充电宝或者电脑上,手机充电接口也已经开发完成,集成在华为手机或者苹果手机上,现在USB设备和手机可以相互充电,这时候就需要开发一个数据线,这跟数据线就是一个双向适配器。
在这里插入图片描述

public class TestAdapter {

    @Test
    public void test(){
        Usb usb = new UsbPhoneAdapter(new Computer(), new HuaweiPhone());
        usb.chargePhone();

        Phone phone = new UsbPhoneAdapter(new Computer(), new HuaweiPhone());
        phone.chargeUsb();
    }

}

双向适配器在实际开发中很少用到。

缺省适配器

缺省适配器模式(Default Adapter Pattern):当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的所有方法的情况,又称为单接口适配器模式。

在这里插入图片描述

public class TestAdapter {

    @Test
    public void test(){
        new UsbLightningAdapter().chargeLightning();
        new UsbTypeCAdapter().chargeTypeC();
    }

}

在JDK类库的事件处理包java.awt.event中广泛使用了缺省适配器模式,如WindowAdapterKeyAdapterMouseAdapter等。

总结

适配器模式有点很多:

  • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构。
  • 增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用。
  • 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。

具体来说,类适配器模式还有如下优点:

由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。

对象适配器模式还有如下优点:

  • 一个对象适配器可以把多个不同的适配者适配到同一个目标;
  • 可以适配一个适配者的子类,由于适配器和适配者之间是关联关系,根据“里氏代换原则”,适配者的子类也可通过该适配器进行适配。

类适配器模式的缺点:

  • Java不支持多重类继承,一次最多只能适配一个适配者类,不能同时适配多个适配者;
  • 适配者类不能为最终类,在Java中不能为final类;
  • 在Java中,类适配器模式中的目标抽象类只能为接口,不能为类,其使用有一定的局限性。

对象适配器模式的缺点如下:
与类适配器模式相比,要在适配器中置换适配者类的某些方法比较麻烦。如果一定要置换掉适配者类的一个或多个方法,可以先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。

使用场景:

  • 在两个完全不相关的系统之间适配,无法获取对接接口的源代码,比如http接口,甚至是跨语言的调用,可以使用适配器来做适配;
  • 需要基于接口开发,但又想复用之前的代码,可以通过适配器达到此目的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值