設計模式06-介面卡模式(Adapter)
阿新 • • 發佈:2021-10-28
對介面卡模式的功能很好理解,就是把一個類的介面變換成客戶端所能接受的另一種介面,從而使兩個介面不匹配而無法在一起工作的兩個類能夠在一起工作。
介面卡的重點在於將一個介面的功能轉換為另一個介面的功能。
介面的實現類中呼叫
第一種是通過持有
設計模式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;
}