- 單一職責原則(Single Reponsibility Principle,SRP)
- 里氏替換原則(Liskov Substitution Principle,LSP)
- 依賴倒置原則(Dependence Inversion Principle,DIP)
- 接口隔離原則(Interface Segregation Principe,ISP)
- 迪米特法則(Law of Demeter,LOD)
- 開閉原則(Open Closed Principle,OCP)
接口隔離原則(ISP)
Interface Segregation Principe,簡稱:ISP。
類的依賴關係應建立在最小接口上,不要都塞在一起。即客戶端不應該依賴它不需要的接口。
問題由來:類A通過接口Interface依賴類B,類C通過接口I依賴類D,如果接口Interface對於類A和類B來說不是最小接口,則類B和類D必須去實現他們不需要的方法。
解決方案:將臃腫的接口Interface拆分爲獨立的幾個接口,類A和類C分別與他們需要的接口建立依賴關係。也就是採用接口隔離原則。
接口隔離原則的含義:建立單一接口,不要建立龐大臃腫的接口,儘量細化接口,接口中的方法儘量少。也就是說,我們要爲各個類建立專用的接口,而不要試圖去建立一個很龐大的接口供所有依賴它的類去調用。在程序設計中,依賴幾個專用的接口要比依賴一個綜合的接口更靈活。接口是設計時對外部設定的“契約”,通過分散定義多個接口,可以預防外來變更的擴散,提高系統的靈活性和可維護性。
接口隔離原則就是要求只提供儘可能小的接口,需要高內聚,不需要的行爲要隱藏起來
說到這裏,很多人會覺的接口隔離原則跟之前的單一職責原則很相似,其實不然。
- 其一,單一職責原則原注重的是職責;而接口隔離原則注重對接口依賴的隔離。
- 其二,單一職責原則主要是約束類,其次纔是接口和方法,它針對的是程序中的實現和細節;而接口隔離原則主要約束接口,主要針對抽象,針對程序整體框架的構建。
採用接口隔離原則對接口進行約束時,要注意以下幾點:
- 接口儘量小,但是要有限度。對接口進行細化可以提高程序設計靈活性是不掙的事實,但是如果過小,則會造成接口數量過多,使設計複雜化。所以一定要適度。
- 爲依賴接口的類定製服務,只暴露給調用的類它需要的方法,它不需要的方法則隱藏起來。只有專注地爲一個模塊提供定製服務,才能建立最小的依賴關係。
- 提高內聚,減少對外交互。使接口用最少的方法去完成最多的事情。
一、舉個例子
繼續拿手機說事兒吧,ICellphone接口有四個方法,分別爲打電話、發短信、上網、網遊戲。Cellphone繼承接口ICellphone,實現了以上四個方法。
代碼如下:
public Interface ICellphone
{
void Call(); //打電話
void Text(); //發短信
void Online(); //上網
void PlayGame(); //玩遊戲
}
public class Cellphone : ICellphone
{
public void Call()
{
Console.WriteLine("User {0} Call", this.GetType().Name);
}
public void Text()
{
Console.WriteLine("User {0} Text", this.GetType().Name);
}
public void Online()
{
Console.WriteLine("User {0} Online", this.GetType().Name);
}
public void PlayGame()
{
Console.WriteLine("User {0} PlayGame", this.GetType().Name);
}
}
以上代碼功能完備,很強大,看起來是不是很完美。當然,單從單一職責上考濾是沒有問題的,但仔細想想,從接口隔離原則的角度出發的話,就不同了。 要是柯南拿一款只能打電話發短信的老人機,那上網和玩遊戲功能是不是就封裝過度了。
因此,這裏需要再修改。將 ICellphone 分割成兩個接口 IBaseCellphone 和 IWebCellphone 。
代碼如下:
//手機基礎功能
public Interface IBaseCellphone
{
void Call(); //打電話
void Text(); //發短信
}
//手機上網和遊戲功能
public Interface IWebCellphone
{
void Online(); //上網
void PlayGame(); //玩遊戲
}
public class Cellphone : IBaseCellphone, IWebCellphone
{
public void Call()
{
Console.WriteLine("打電話");
}
public void Text()
{
Console.WriteLine("發短信");
}
public void Online()
{
Console.WriteLine("手機已連網");
}
public void PlayGame()
{
Console.WriteLine("開始玩遊戲");
}
}
場景中使用:
/// <summary>
/// 現實生活中的場景,使用手機
/// </summary>
public class People
{
public int Id { get; set; }
public string Name { get; set; }
/// <summary>
/// 一些人只使用手機的基本功能
/// </summary>
/// <param name="phone"></param>
public void UsePhone(IBaseCellphone cellphone)
{
Console.WriteLine("我是 {0},我只用基礎的功能", this.Name);
cellphone.Call();
cellphone.Text();
}
/// <summary>
/// 只想上網玩遊戲
/// </summary>
/// <param name="cellphone"></param>
public void PlayOnlineGame(IWebCellphone cellphone)
{
Console.WriteLine("我是 {0},我只想上網玩遊戲", this.Name);
cellphone.Online();
cellphone.PlayGame();
}
}