必要的介面

2015 年 10 月 12 日

必要的介面是由互動客戶端定義的介面,用於指定供應元件在互動中需要執行的動作。

「可比較」介面是一個必要的介面範例。此類介面通常是排序功能所需要的。假設我有一組專輯,我想依照標題排序,但忽略「The」、「A」和「An」等冠詞。我可以透過實作任何排序功能的必要介面,讓專輯以這種方式排序。

在 Java 中,它會類似這樣。

class Album...

  public class Album implements Comparable<Album> {
    private String title;
  
    public Album(String title) {
      this.title = title;
    }
    public String getTitle() {
      return title;
    }
  
    @Override
    public int compareTo(Album o) {
      return this.sortKey().compareTo(o.sortKey());
    }
    private String sortKey() {
      return ignoreSortPrefixes(title).toLowerCase();
    }
    private static String ignoreSortPrefixes(String arg) {
      final String[] prefixes = {"an", "a", "the"};
      return Arrays.stream(prefixes)
              .map(s -> s + " ")
              .filter(s -> arg.toLowerCase().startsWith(s))
              .findFirst()
              .map(s -> arg.substring(s.length(), arg.length()))
              .orElse(arg)
              ;
    }

在本例中,Comparable 是各種 Java 排序功能的必要介面。更複雜的範例可能會有更豐富的介面,並在其中定義多種方法。

人們通常認為介面是供應商關於對客戶端公開什麼內容的決策。但必要的介面是由客戶端指定(且通常定義)的。透過思考客戶端需要什麼,你通常可以獲得更有用的介面,這會引導你思考 角色介面

使用適配器

如果我想將兩個獨立定義的模組整合在一起,會出現一個常見的問題。即使我們獲得相符的名稱,我們也可能會遇到困難。

考慮一個任務清單,其必要的介面為任務。

class TaskList...

  private List<Task> tasks;
  private LocalDate deadline;
  public LocalDate latestStart() {
    return deadline.minusDays(tasks.stream().mapToInt(t -> t.shortestLength()).sum());
  }
}

interface Task…

  int shortestLength();

假設我想將它與從不同供應商取得的 Activity 類別整合。

class Activity…

  public int shortestLength() {
    …

即使活動有一個方法簽章剛好與必要的介面相符,我(正確地)無法建立活動的任務清單,因為類型定義不符。如果我無法修改活動類別,我需要使用適配器。

public class ActivityAdapter implements Task {
  private Activity activity;

  public ActivityAdapter(Activity activity) {
    this.activity = activity;
  }
  @Override
  public int shortestLength() {
    return activity.shortestLength();
  }
}

在軟體世界中,我們很自由地使用適配器這個術語,但這裡我嚴格按照 四人幫書籍 的意義來使用。在此用法中,適配器是一個將一個物件對應到另一個物件的必要介面的物件。

在本例中,如果我使用的是動態語言,我不需要適配器,但如果活動類別使用具有不同簽章的方法,我則需要適配器。

致謝

Alexander Zagniotov 和 Bruno Trecenti 對本文草稿提出評論。