設計原則之接口分離原則(ISP)

簡介

單一職責原則傾向於設計視角,接口分離原則傾向於實現視角,兩者看起來很是類似,可是在某些方面仍是有所區別的。java

定義

接口分離原則(Interface Segregation Principle):使用方不該該依賴於它不使用的方法(no client should be forced to depend on methods it does not use.)。ide

ISP 原則是用來處理胖接口或胖基類的,接口或類中包含了茫茫多的方法就稱爲胖接口或胖基類(簡稱小胖吧)。使用方在使用小胖的時候,會發現本身沒有必要實現某個方法,但因爲在小胖中存在,本身不得不實現一個,要麼是空方法,要麼拋出異常以代表本身不支持。網站

這時候就須要 ISP 原則出場了,它指導你將接口劃分紅更小的粒度,使用方只須要實現本身須要的接口便可,而不用繼承小胖致使不得不實現小胖交代下來的任務。編碼

實踐

設計原則只里氏替換原則中,咱們舉的例子就違反了接口分離原則,這裏再舉一個例子說明這個原則。設計

需求要求咱們作一個二手書設計,要求咱們記錄書的基本信息,收購的基本信息,以及二手書的鑑定信息等信息。code

設計的接口以下:繼承

public interface Book {
    public String isbn();
    public String author();
    public Date publishDate();
    public PublisherInfo publisher();
    public PurchaseInfo purchaseInfo();
    public IdentificationInfo identificationInfo();
}

接口工做良好,很好的支持了網站的運行。但因爲業務的變化,網站如今不單單要賣二手書了,還要賣新書。這時只是缺乏了收購信息和鑑定信息,可是新書本質上仍是書,所以咱們直接實現了 Book 接口來賣新書。接口

public abstract class NewBook implements Book {
    public PurchaseInfo purchaseInfo() {
        return null;
    }
    public IdentificationInfo identificationInfo() {
        return null;
    }
}

全部的新書都使用 NewBook 接口,改動也很小就支持了新書的銷售,很美好。ip

這個設計就違反了 ISP 原則,Book 強制全部的書都必須有收購信息和鑑定信息,但新書卻並無這兩項,將新書實現 Book 接口強制新書也必需要有這兩項信息,無奈只能使用折中辦法返回null。ci

要改變這種狀況,咱們須要將收購信息和鑑定信息單獨拆到一個接口中,二手書的實現繼承這個接口,而新書的實現不繼承這兩個接口。

public interface Book {
    public String isbn();
    public String author();
    public Date publishDate();
    public PublisherInfo publisher();
    public PurchaseInfo purchaseInfo();
    public IdentificationInfo identificationInfo();
}

public interface SecondHand {
    public PurchaseInfo purchaseInfo();
    public IdentificationInfo identificationInfo();
}

接口拆分紅這樣已經知足網站的要求了,若是後面網站發展愈來愈大,鑑定成本不可承受時,有些書籍不做鑑定直接入庫,這時咱們就須要將 SecondHand 接口再拆分紅兩個接口,將收購信息和鑑定信息分離開來,不做耦和。

與 SRP 的比較

SRP 原則說的是一個類只能有一個改變的理由,ISP 原則指的是使用方不該該依賴它不使用的方法。有的設計符合 SRP 原則卻並不符合 ISP 原則。

舉一個例子,正常的 Stack 都有 push pop 方法,若是使用方有一個使用場景,只能使用 push, 不能使用 pop, 那麼使用方就不能繼承 Stack 來實現本身的功能,與 ISP 原則相悖。可是原始的 Stack 設計是徹底符合 SRP 原則的,pushpop 就是它本身的職責。

從這個例子能夠看出,ISP 原則不單單能指導咱們分離接口,還能幫助判斷一個類的繼承是否是合理的。

可能有的人以爲這個例子牽強,誰會限制一個 Stack 不能有 pop 方法。你們能夠去看下Java 中的 Stack 實現,它繼承了Vector ,而 Vector 是一個 ListStack 應該只能壓入彈出的,可是卻繼承了 Listadd,remove,get 等方法,是一個很糟糕的實現設計。

總結

接口分離原則與單一職責原則挺相近,但在某些點上是有區別的。平常編碼實現某個接口、繼承某個類時,問問本身,這樣符合 ISP 原則麼?

Reference

  1. Interface segregation principle
  2. Understand Single Responsibility and Interface Seg
  3. In SOLID, what is the distinction between SRP and ISP? (Single Responsibility Principle and Interface Segregation Principle)
相關文章
相關標籤/搜索