1. 程式人生 > 其它 >設計模式06-介面卡模式(Adapter)

設計模式06-介面卡模式(Adapter)

對介面卡模式的功能很好理解,就是把一個類的介面變換成客戶端所能接受的另一種介面,從而使兩個介面不匹配而無法在一起工作的兩個類能夠在一起工作。 介面卡的重點在於將一個介面的功能轉換為另一個介面的功能。

設計模式06-介面卡模式(Adapter)

概述

對介面卡模式的功能很好理解,就是把一個類的介面變換成客戶端所能接受的另一種介面,從而使兩個介面不匹配而無法在一起工作的兩個類能夠在一起工作。

介面卡的重點在於將一個介面的功能轉換為另一個介面的功能。

優點

  • 更好的複用性

系統需要使用現有的類,而此類的介面不符合系統的需要。那麼通過介面卡模式就可以讓這些功能得到更好的複用。

  • 更好的擴充套件性

在實現介面卡功能的時候,可以呼叫自己開發的功能,從而自然地擴充套件系統的功能。

缺點

過多的使用介面卡,會讓系統非常零亂,不易整體進行把握。比如,明明看到呼叫的是A介面,其實內部被適配成了B介面的實現,一個系統如果太多出現這種情況,無異於一場災難。因此如果不是很有必要,可以不使用介面卡,而是直接對系統進行重構。

簡單實現

JDK實現

1、已有 Source 介面及其實現類 SourceImpl

public interface Source {
    void execute();
}

public class SourceImpl implements Source {
    @Override
    public void execute() {
    }
}

2、現在要在使用 Target 介面處呼叫 Source 介面方法而不修改 Source 相關類。

public interface Target {
    void executeTarget();
}

3、可以通過兩種適配方式來在 Target

介面的實現類中呼叫 Source 實現類的功能。
第一種是通過持有 Source 實現類物件的方式來呼叫 Source 方法,相比於下述的繼承方式,更推薦通過組裝的方式完成 Source 介面的適配。

public class HoldObjectAdapter implements Target {
    private final Source source;
    
    HoldObjectAdapter(Source source) {
        super();
        this.source = source;
    }
    
    @Override
    public void executeTarget() {
        source.execute();
    }
}

第二種是通過繼承 Source 實現類的方式來呼叫 Source 方法。

public class ExtendClassAdapter extends SourceImpl implements Target {
    @Override
    public void executeTarget() {
        execute();
    }
}

原始碼解析

JDK

java.io.InputStreamReader

public class InputStreamReader extends Reader {
    private final StreamDecoder sd;
    public InputStreamReader(InputStream in) {
        // ...
    }
}

InputStreamReader 通過持有不同介面或父類 InputStream 型別的實現來將 InputStream 適配適配到 Reader

Mybatis Log

org.apache.ibatis.logging.Log

public interface Log {
    // ...
}

Mybatis 為了適配多種日誌實現類,就使用了介面卡模式,將多種日誌的實現適配為同一個介面 Log 的實現。

org.apache.ibatis.logging.log4j2.Log4j2LoggerImpl

// ...
import org.apache.logging.log4j.Logger;

public class Log4j2LoggerImpl implements Log {
    private static final Marker MARKER = MarkerManager.getMarker(LogFactory.MARKER);
    // 這裡就適配了 apache 的 log4j2 日誌實現類
    private final Logger log;
    public Log4j2LoggerImpl(Logger logger) {
        log = logger;
    }
}

org.apache.ibatis.logging.slf4j.Slf4jLoggerImpl

class Slf4jLoggerImpl implements Log {
    private final Logger log;
    // 這裡就適配了 slf4j 的日誌實現類
    public Slf4jLoggerImpl(Logger logger) {
        log = logger;
    }