何为适配器模式

适配器模式是将一个类的接口转换成客户期望的另一个接口。适配器让两个不兼容的类可以合作。

适配器模式有两种,一种是类适配器,另一种是对象适配器。相关的类图分别如下。

类适配器

对象适配器

很遗憾,类适配器需要多继承,而多继承在 Java 中是不允许的,所以在 Java 中适配器模式指的是对象适配器。

适配器模式在生活中非常常见。比如我要去香港玩,需要备好手机充电器,可是经过了解之后发现香港那边的墙上插座是“三脚品字形”,而在内陆“两扁平行”和“三扁八字形带接地”比较常见,所以我们需要一个转接器(适配器)将自带的充电口插入到转接器上,转接器再插到“品字形”插座上,这样就能在香港给手机充电了。

在 JAVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口,这时就需要适配器模式。

示例 1

创建两个接口,一个香港的插座接口,一个内陆的插座接口。同时还需要实现一个转内陆插头的转接器。

1、香港的插座接口

public interface HongKongSocket {

    // 充电的具体设备名称
    void setDevice(String device);

    // 获取设备名称
    String getDevice();

    // 充电
    void charge();

}

2、内陆的插座接口

public interface NativeSocket {

    void setDevice(String device);

    String getDevice();

    void charge();

}

3、创建适配器(香港 -> 内陆)

public class SocketAdapter implements HongKongSocket {

    NativeSocket nativeSocket;

    public SocketAdapter(NativeSocket nativeSocket) {
        System.out.println("有新接口接入适配器:" + nativeSocket);
        this.nativeSocket = nativeSocket;
    }

    @Override
    public void setDevice(String device) {
    }

    @Override
    public String getDevice() {
        return null;
    }

    @Override
    public void charge() {
        System.out.println("适配器开始传输电...");
        nativeSocket.charge();
    }
}

4、苹果手机的接口

import java.util.Objects;

public class IPhoneChargeSocket implements NativeSocket {

    private String device;

    @Override
    public void setDevice(String device) {
        this.device = device;
    }

    @Override
    public String getDevice() {
        return device;
    }

    @Override
    public void charge() {
        if (Objects.isNull(device) || device.isBlank()) {
            System.out.println("没有设备接入");
            return;
        }

        System.out.println("正在充电:" + device);
    }

}

5、测试

public class TestAdapter {

    public static void main(String[] args) {

        NativeSocket chargeSocket = new IPhoneChargeSocket();
        chargeSocket.setDevice("IPhone 14 Pro Max");

        SocketAdapter socketAdapter = new SocketAdapter(chargeSocket);
        socketAdapter.charge();

    }
}

6、运行

有新接口接入适配器:com.example.demo_springboot.designpattern.adapter.IPhoneChargeSocket@327471b5
适配器开始传输电...
正在充电:IPhone 14 Pro Max

示例 2

将以前系统的 Enumeration 接口转化为 Iterator 接口。

import java.util.Enumeration;
import java.util.Iterator;

public class IteratorAdapter<E> implements Iterator<E> {
    
    Enumeration<E> enumeration;
    
    public IteratorAdapter(Enumeration<E> enumeration) {
        this.enumeration = enumeration;
    }
    
    @Override
    public boolean hasNext() {
        return enumeration.hasMoreElements();
    }

    @Override
    public E next() {
        return enumeration.nextElement();
    }

    @Override
    public void remove() {
        Iterator.super.remove();
    }
}