設計模式學習筆記(八)介面卡模式介紹及其應用

歸斯君發表於2022-03-29

介面卡模式(Adapter)指的是將一個類的介面轉換成另一個可以相容的介面。比如我們日常生活中的轉換頭、古早時期使用的電池萬能充,就相當於程式中使用的介面卡模式。

image-20220329210951114

一、介面卡模式的介紹

1.1 介面卡模式的結構

介面卡模式模式主要分為類結構型模式和物件結構型模式兩種:

1.1.1 類介面卡模式

類介面卡模式通過多重繼承,將一個介面與另一個介面進行匹配。而對於一些面嚮物件語言如C#、Java不支援多重繼承,那麼我們就可以繼承一個類,同時實現多個介面來達到介面卡的效果。如下圖所示:

image-20220329214512809

  • Adaptee:適配者類,它是需要被訪問的、需要被適配的元件
  • Target:目標介面,當前系統業務所使用的介面,可以是抽象類或介面
  • Adapter:介面卡類,通過繼承和實現目標介面,讓客戶端按照目標介面的方法訪問適配者
  • Client:客戶端,介面卡的使用者

1.1.2 物件介面卡模式

物件介面卡模式相對於類介面卡的不同點在於,物件介面卡中適配者類和介面卡類的耦合度要更低。如下圖所示:

image-20220329215848876

  • Adaptee:適配者類,它是需要被訪問的、需要被適配的元件
  • Target:目標介面,當前系統業務所使用的介面,可以是抽象類或介面
  • Adapter:介面卡類,通過聚合和實現目標介面,讓客戶端按照目標介面的方法訪問適配者
  • Client:客戶端,介面卡的使用者

1.2 介面卡模式的應用實現

我們可以根據上面兩種模式分別進行實現:

1.2.1 類介面卡實現程式碼

//適配者類
public class Adaptee {
    public void specificRequest(){
        System.out.println("我是適配者類");
    }
}
//目標介面
public interface Target {
    public void request();
}
//介面卡類
public class Adapter extends Adaptee implements Target{
    @Override
    public void request() {
        specificRequest();
    }
}
//客戶端類
public class Client {
    public static void main(String[] args) {
        Target target = new Adapter();
        target.request();
    }
}

1.2.2 物件介面卡實現程式碼

//適配者類
public class Adaptee {
    public void specificRequest(){
        System.out.println("我是適配者類");
    }
}
//物件介面卡類
public class ObjectAdapter implements Target{

    private Adaptee adaptee;

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

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}
//客戶端類
public class Client {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new ObjectAdapter(adaptee);
        target.request();
    }
}

我們發現,物件介面卡模式是在介面卡類中引入了適配者,這樣就利用聚合的方式將兩個類連線在一起。而根據設計原則,聚合優先於繼承,所以在我們日常的使用中,應該多選擇物件介面卡模式。

三、介面卡的應用場景

3.1 MyBatis中的日誌適配應用

在MyBatis 中的典型代表是日誌模組,比如其中適配了slf4jApache Commons LoggingLog4j2JDK logging等的日誌型別,下面來看看具體實現:

//統一的Log介面
public interface Log {
  boolean isDebugEnabled();
  boolean isTraceEnabled();
  void error(String s, Throwable e);
  void error(String s);
  void debug(String s);
  void trace(String s);
  void warn(String s);
}

MyBatis 定義了多個日誌型別的介面卡,以Log4j2實現為例:

public class Log4j2Impl implements Log {

  private final Log log;

  public Log4j2Impl(String clazz) {
    Logger logger = LogManager.getLogger(clazz);
    if (logger instanceof AbstractLogger) {
      log = new Log4j2AbstractLoggerImpl((AbstractLogger) logger);
    } else {
      log = new Log4j2LoggerImpl(logger);
    }
  }

  @Override
  public boolean isDebugEnabled() {
    return log.isDebugEnabled();
  }

  @Override
  public boolean isTraceEnabled() {
    return log.isTraceEnabled();
  }

  @Override
  public void error(String s, Throwable e) {
    log.error(s, e);
  }

  @Override
  public void error(String s) {
    log.error(s);
  }

  @Override
  public void debug(String s) {
    log.debug(s);
  }

  @Override
  public void trace(String s) {
    log.trace(s);
  }

  @Override
  public void warn(String s) {
    log.warn(s);
  }
}

所以在專案新增Log4j2後,就可以直接使用它列印MyBatis的日誌資訊。

3.2 營銷系統中的各種MQ訊息或介面的適配應用

相關文章