【設計模式】抽象類與接口

一、抽象類


// 抽象類
public abstract class Logger {
  private String name;
  private boolean enabled;
  private Level minPermittedLevel;

  public Logger(String name, boolean enabled, Level minPermittedLevel) {
    this.name = name;
    this.enabled = enabled;
    this.minPermittedLevel = minPermittedLevel;
  }
  
  public void log(Level level, String message) {
    boolean loggable = enabled && (minPermittedLevel.intValue() <= level.intValue());
    if (!loggable) return;
    doLog(level, message);
  }
  
  protected abstract void doLog(Level level, String message);
}
// 抽象類的子類:輸出日誌到文件
public class FileLogger extends Logger {
  private Writer fileWriter;

  public FileLogger(String name, boolean enabled,
    Level minPermittedLevel, String filepath) {
    super(name, enabled, minPermittedLevel);
    this.fileWriter = new FileWriter(filepath); 
  }
  
  @Override
  public void doLog(Level level, String mesage) {
    // 格式化level和message,輸出到日誌文件
    fileWriter.write(...);
  }
}
// 抽象類的子類: 輸出日誌到消息中間件(比如kafka)
public class MessageQueueLogger extends Logger {
  private MessageQueueClient msgQueueClient;
  
  public MessageQueueLogger(String name, boolean enabled,
    Level minPermittedLevel, MessageQueueClient msgQueueClient) {
    super(name, enabled, minPermittedLevel);
    this.msgQueueClient = msgQueueClient;
  }
  
  @Override
  protected void doLog(Level level, String mesage) {
    // 格式化level和message,輸出到消息中間件
    msgQueueClient.send(...);
  }
}
  1. 抽象類不能被實例化,只能被繼承。不能同過new方法去實例化一個抽象類
  2. 抽象類可以包括屬性和方法。方法可以包括實現,即普通方法; 方法也可以不包括實現,即抽象方法。
  3. 子類繼承抽象類,必須實現抽象類中的抽象方法。若沒有實現,運行將會報錯

二、接口類


// 接口
public interface Filter {
  void doFilter(RpcRequest req) throws RpcException;
}
// 接口實現類:鑑權過濾器
public class AuthencationFilter implements Filter {
  @Override
  public void doFilter(RpcRequest req) throws RpcException {
    //...鑑權邏輯..
  }
}
// 接口實現類:限流過濾器
public class RateLimitFilter implements Filter {
  @Override
  public void doFilter(RpcRequest req) throws RpcException {
    //...限流邏輯...
  }
}
// 過濾器使用demo
public class Application {
  // filters.add(new AuthencationFilter());
  // filters.add(new RateLimitFilter());
  private List<Filter> filters = new ArrayList<>();
  
  public void handleRpcRequest(RpcRequest req) {
    try {
      for (Filter filter : fitlers) {
        filter.doFilter(req);
      }
    } catch(RpcException e) {
      // ...處理過濾結果...
    }
    // ...省略其他處理邏輯...
  }
}
  1. 接口不能包含屬性(即不能包含成員變量)
  2. 接口類中只能聲明方法,不能包含方法的實現(這點類似抽類中的抽象方法)
  3. 類實現抽象接口時,必須實現其中所有的抽象方法

        抽象類與接口類的對比來講,抽象類可以包含屬性,主要是爲解決代碼複用的問題,和子類繼承是is-a的關係。

        接口類是爲了解決解耦問題,調用者更多隻需關注抽象接口,不需要關注實現。也是“基於接口而非實現進行編程”的體現。表示的一種has-a的關係。

在解決代碼複用的問題上,如果單純的用繼承,勢必要在父類中增加一些沒有實現的方法,在代碼閱讀是增加負擔,同時調用者在未能全部熟悉代碼的前提下,忘記填寫實現方法,在調用的時候會出錯。同時可以實例化該父類也是危險的。

關於抽象類和接口類的使用:

抽象類是一種自下而上設計思路,先有代碼重複,抽象出一個類,解決代碼複用問題。這裏重點要區別現有單純的繼承,單純的繼承父類會被實例化,防止從而調用了沒有實現的方法(同時沒有報錯)。

接口類是一種自上而下設計思路,先設計好接口,再去實現。

 

發佈了19 篇原創文章 · 獲贊 0 · 訪問量 7937
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章