介面隔離原則(Interface Segregation Principle,ISP)
介面隔離原則的目的是讓每個類別都有明確的職責,避免出現「胖」介面或「胖」類別,也就是包含了太多不相關的方法的介面或類別。
核心思想是避免"胖接口"(Fat Interface)或"全能接口"(God Interface),即一個包含了過多方法的接口。
可能各位有看到名稱,
會認為ISP是為了Interface而來的。
但要說的一點是其實在其他地方也會使用ISP,
ISP的目的是讓每個類別都有明確的職責,
所以不論是interface或class,
只要是包含了太多不相關的function、屬性、class,
都可以是違反ISP。
public abstract class CarInfomationModel : VehicleModel
{
public string Gasoline { get; set; }
public string Rate { get; set; }
public string Supplier { get; set; }
public string Color { get; set; }
...
public override void Move()
{
Console.WriteLine("Car is moving...");
}
}
public class bicycleModel : CarInfomationModel
{
}
它的定義為載具,
可如果是一些沒有辦法計算距離的載具,
例如腳特車,
那麼MovingDistance或就有可能會是違反了,
然後由於bicycleModel繼承了CarInfomationModel,
裡面可能就有許多bicycle所不需要的屬性,
像是安全帶、冷氣等等。
所以介面隔離原則並不是只適用於介面,也適用於抽象類別或具體類別,避免出現「胖」介面或「胖」類別,也就是包含了太多不相關的方法的介面或類別。
那麼如何避免呢?
最常見德是將大型的介面分割成更小、更具體的部分,從而避免客戶端需要實現它們不需要的方法。
例如把Move與MovingDistance各自拆分為單獨的一部分,
那麼原先bicycleModel就沒必要去繼承CarInfomationModel而是改繼承,
那些單一的一部分就可以進行。
那麼說道單一的一部分,
有些人會想起SRP,
雖然都是致力於更為簡潔,
但是它們的方向性不太一樣。
SRP是強調類別的職責,
也就是說只有對一個地方進行負責,並且不會影響到其他地方,
就像是從一個地方,看他不會影響到多個地方,就會是SRP。
而ISP是從client看進去,
更像是一種框架,是一種設計層面。
舉個比較不準確的例子:
筆者的程式碼,
主要是為了取的車子詳細資訊,
從client的角度看過去,
這邊會預期取得跟車子有關的任何資訊,
包含車主姓名是筆者,
筆者又會執行顯示到筆者手機的型號。
那麼對於client的預期來說,
筆者手機的型號是毫無作用的,
所以不符合ISP。
但筆者的手機的型號,
是只能由筆者進行改變的小模組,
那麼會符合SRP,
但如果從車子的詳細資訊來看,
筆者的手機型號出現,
就是混淆了單一職責。
在分割的過程中不能違反SRP,
只不過SRP是以開發角度去設計的,
注重的是職責。
然而ISP是以用戶端角度去分割的,注重的是對介面的依賴隔離,
筆者認為當模組遵守SRP後依照用戶需求再去分離客製與抽象介面,進而設計框架。