设计模式(9):适配器模式及其应用

适配器模式

1、什么是适配器模式

2、适配器模式的特性

3、适配器模式的优缺点及应用场景

4、适配器模式示例

4.1、对象适配器模式示例

4.2 类适配器模式示例

5、适配器模式在Spring源码中的典型应用


1、什么是适配器模式

适配器模式定义:将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容不能在一起工作的那些类可以一起工作。适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。

现实中的典型适配器例子:读卡器,电源适配器....

适配器模式的实现主要分对象适配器模式和类适配器模式,类图结构示例如下:

2、适配器模式的特性

(1)意图:

将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

(2)主要解决:

主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。

(3)何时使用: 

1)系统需要使用现有的类,而此类的接口不符合系统的需要。

2)想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。

3)通过接口转换,将一个类插入另一个类系中。

(4)如何解决:

继承或依赖(推荐)。

(5)关键代码:

适配器继承或依赖已有的对象,实现想要的目标接口。

3、适配器模式的优缺点及应用场景

(1)优点: 

1)可以让任何两个没有关联的类一起运行。

2)提高了类的复用。

3)增加了类的透明度。

4)灵活性好。

(2)缺点: 

1)过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。

2)由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

(3)使用场景:

有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。

(4)注意事项:

适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。

4、适配器模式示例

适配器模式的实现主要有对象适配器模式和类适配器模式,其中,对象适配器模式通过组合来实现;类适配器模式使用继承和实现,一般情况下,建议使用对象适配器模式实现而尽量少用类适配器实现。

4.1、对象适配器模式示例

1)示例场景:

假设要实现一个电源适配器,将输出220v电压的输出适配成输出5v电源输出。

(2)代码示例如下:

原始输出类:

//原始输出
class Adaptee{
    public int output220V(){
        return 220;
    }
}

目标输出接口:

//目标接口
interface Target{
    int output5v();
}

对象适配器类,通过组合来实现:


//对象适配器,通过组合关系来实现
class Adapter implements Target{

    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public int output5v() {
        int i = adaptee.output220V();
        //...一系列转换操作
        System.out.println(String.format("原始电压:%d v -> 输出电压:%d v",i,5));
        return 5;
    }
}

使用测试示例:

public class ObjectAdapterTest {

    public static void main(String[] args) {
        //将原始的输出电压进行适配输出5v电压
        Adaptee adaptee = new Adaptee();

        Target target = new Adapter(adaptee);
        target.output5v();
    }
}

结果输出示例:

原始电压:220 v -> 输出电压:5 v

4.2 类适配器模式示例

(1)场景同上:

假设要实现一个电源适配器,将输出220v电压的输出适配成输出5v电源输出。

(2)代码示例:

原始输出类:

//原始输出
class Adaptee2{
    public int output220V(){
        return 220;
    }
}

目标接口类:

//目标输出接口
interface Target2{
    int output5v();
}

 适配器类,通过继承来实现:

//类的适配器模式:通过继承关系来实现
class Adapter2 extends Adaptee2 implements Target2{
    @Override
    public int output5v() {
        int i = output220V();
        //...一系列转换操作
        System.out.println(String.format("原始电压:%d v -> 输出电压:%d v",i,5));
        return 5;
    }
}

 测试示例:

public class ClassAdapterTest {

    public static void main(String[] args) {
        Adapter2 adapter2 = new Adapter2();
        adapter2.output5v();
    }
}

测试结果输出示例:

原始电压:220 v -> 输出电压:5 v

可以看出,对象适配器实现和类适配实现均可完成适配器功能的实现,但是类适配器使用的是继承方式实现,在实现接口方法的同时也继承了原始父类的方法。对应Adapter类而言,多了不必要的方法,这往往对Adapter类的设计目的而言是没有意义的,还会容易误解。一般情况下,推荐使用对象适配模式来吧实现适配器模式。 

5、适配器模式在Spring源码中的典型应用

(1)Spring中的应用监听器ApplicationListener(旧接口)和GenericApplicationListener(新接口)中,为了兼容新旧监听器,它们之间的适配使用了适配器模式,使用的是对象适配器模式;(注ApplicationListener本身使用的是观察者模式)

(2)java.util包中的Arrays类的asList方法,也使用的适配器模式。该方法源码如下:

 @SafeVarargs
    @SuppressWarnings("varargs")
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

这里直接new一个List对象进行返回。new ArrayList()方法源码如下:

private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable{

        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }

        //其他方法....
}

这里通过直接将输入数组转换成一个泛型数组,从而实现了将对象转换为List对象。

 

 

本文源代码:

https://github.com/JianfuYang/2020-yjf-review/tree/master/src/designpatterns/adapter

 

声明:本文部分内容整理来源于网络,仅做个人学习使用!侵删~

本文部分内容参考链接:

https://www.runoob.com/design-pattern/adapter-pattern.html

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值