设计模式——适配器模式

138 阅读3分钟

概述

通常情况下客户端通过目标类的接口来访问它提供的方法,但有时,虽然现有类可以满足客户类的功能需要,但他提供的接口不一定是客户类期望的,这可能是因为现有类的方法名与目标类中定义的方法名不一致等原因导致的。

因此 现有的接口需要转化为客户类期望的接口,而适配器模式是把一个类的接口变化成客户类期待的另一个接口,从而使原本因接口不一致无法一起工作的两个类能一起工作。

该模式下涉及到的角色如下图所示:

适配器模式分为类的适配器模式对象的适配器模式


类的适配器

示例

以手机充电线为例,以往的手机大多数Micro USB接口,必须使用Micro USB充电线,而现在新出了一部使用type-c接口的手机,它,必须使用type-c充电线。为避免浪费已有的Micro USB的充电线,我们可以使用type-c转接口(类适配器),这样我们就可以使用Micro USB充电线来插上type-c接口的手机

首先是目标接口(手机接口类型的大致定义):

public interface cellPhone_interface {
    public void connection(); 
}

实现接口的适配者TypeC类

class TypeC implements cellPhone_interface {
    @Override
    public void connection() {
        System.out.println("需要使用TypeC连接...");
    }
}

被适配者MUSB

public class MUSB{
    public void connection(){
        System.out.println("需要使用Micro USB充电线");
    }
}

最后是适配器角色Adapter类,它实现了目标接口,并扩展了被适配者。它实现的connection方法负责将Typec转为MUSB接口,这样我们就可以使用MUSB充电线了。

public class Typec_Adapter extends MUSB implements cellPhone_interface {
    @Override
    public void connection() {
        System.out.println("插入 type-c 转接头");
        super.connection();
    }
}

最后测试一下:

public class Test {
    public static void main(String[] args) {
        //使用TypeC接口
        cellPhone_interface  tc = new TypeC ();
        tc.connection();
        //使用转接头
        cellPhone_interface adapter = new Typec_Adapter ();
        adapter.connection();
    }
    /*
        输出:
            需要使用TypeC连接...
            插入 type-c 转接头
            需要使用Micro USB充电线
    */
}

对象适配器

同样以手机接口为例,我们修改一下转接口类,在转接口类中定义一个目标接口实例。

class Typec_Adapter  implements cellPhone_interface {
    private cellPhone_interface cpi;

    public Typec_Adapter(cellPhone_interface cpi) {
        this.cpi = cpi;
    }

    @Override
    public void connection() {
        System.out.println("插入 type-c 转接头");
        cpi.connection();
    }
}

测试一下:

public class AdapterMain {
    public static void main(String[] args) {
        //传入的参数为MUSB类
        cellPhone_interface  adapter = new Typec_Adapter(new MUSB());
        adapter.connection();
    }
}

总结

适配器模式的优点

(1)可以让两个没有关联的类一起运行(本例中的两个手机接口类)

(2)提高了类的复用,想使用现有的类(本例中的typec接口类),而此类的接口标准又不符合现有系统的需要。

缺点

过多使用会导致系统凌乱,追溯困难,比如内部转发导致调用A适配成B。

适配器模式的使用场景

(1)系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系统的需要,甚至没有这些类的源代码。

(2)想创建一个可以重复使用的类,用于与 一些彼此之间没有太大关联的一些类,在将来可能被一起引进的类一起工作。

两个模式的区别

(1)类适配器:采用对象继承的方式来实现适配功能

(2)对象适配器:采用对象的组合的方式来实现适配功能。


JDK中使用到适配器模式的类

Java I/O 库大量使用了适配器模式,比如说:

(1)FileInputStream 类,它继承自InputStream,同时它持有一个FileDiscriptor 对象的引用。它使用了将FileDiscriptor对象适配成InputStrem 类型的对象形式适配器。

public class FileInputStream extends InputStream {
    private final FileDescriptor fd;
    public FileInputStream(FileDescriptor fdObj) {
        SecurityManager security = System.getSecurityManager();
        if (fdObj == null) {
            throw new NullPointerException();
        }
        if (security != null) {
            security.checkRead(fdObj);
        }
        fd = fdObj;
        path = null;
        fd.attach(this);
    }

同样FileOutputStream类也是类似的道理。

(2)StringReader 是一个适配器类,它继承 Reader 类型,持有一个对 String 对象的引用。它将 String 的接口适配成 Reader 类型的接口。


参考资料

一起学设计模式 - 适配器模式