1.定義
客戶端不應該依賴它不需要的接口;
一個類對另一個類的依賴應該建立在最小的接口上。
2.定義解讀
定義包含三層含義:
- 一個類對另一個類的依賴應該建立在最小的接口上;
- 一個接口代表一個角色,不應該將不同的角色都交給一個接口,因為這樣可能會形成一個臃腫的大接口;
- 不應該強迫客戶依賴它們從來不用的方法。
接口隔離原則有點像單一職責原則,但是也有區別,在單一職責原則中,一個接口可能有多個方法,提供給多種不同的調用者所調用,但是它們始終完成同一種功能,因此它們符合單一職責原則,卻不符合接口隔離原則,因為這個接口存在着多種角色,因此可以拆分成更多的子接口,以供不同的調用者所調用。比如說,項目中我們通常有一個Web服務管理的類,接口定義中,我們可能會將所有模塊的數據調用方法都在接口中進行定義,因為它們都完成的是同一種功能:和服務器進行數據交互;但是對於具體的業務功能模塊來說,其他模塊的數據調用方法它們從來不會使用,因此不符合接口隔離原則。
3.優點
使用接口隔離原則,意在設計一個短而小的接口和類,符合我們常說的高內聚低耦合的設計思想,從而使得類具有很好的可讀性、可擴展性和可維護性。
4.問題提出
類A通過接口I依賴類B,類C通過接口I依賴類D,如果接口I對於類A和類C來說不是最小接口,而類B和類D必須去實現它們不需要的方法。下面通過一個UML圖來說明這種現象:
在這里,我們定義了一個動物活動的接口IAnimal,里面有4個方法:飛行fly、行走walk、吃eat和工作work,然后分別用人類People和鳥類Bird實現了這個接口。中國人類ChinesePeople和鸚鵡類Parrot通過接口IAnimal分別依賴類People和類Bird。很明顯,對於ChinesePeople來說,fly方法是多余的,因為人不會飛;對於Parrot類來說,work方法是多余的,因為鸚鵡不需要工作。接口IAnimal對於類ChinesePeople和類Parrot來說不是最小接口。
5.解決方案
將臃腫的接口IAnimal拆分為獨立的幾個接口,類ChinesePeople和類Parrot分別與它們需要的接口建立依賴關系,也就是采用接口隔離原則。修改后的UML圖如下所示:
6.示例
import Foundation @objc protocol IAnimal { optional func walk(); func eat(); } protocol IPeople { func work(); } protocol IBird { func fly(); } class People: NSObject, IAnimal, IPeople { func walk() { print("People walk"); } func eat() { print("People eat"); } func work() { print("People work"); } } class Bird: NSObject, IAnimal, IBird { func eat() { print("Bird eat"); } func fly() { print("Bird Fly"); } } class ChinesePeople { var chinesePeople: protocol<IAnimal, IPeople>?; func peopleWalk() { chinesePeople?.walk!(); } func peopleEat() { chinesePeople?.eat(); } func peopleWork() { chinesePeople?.work(); } } class Parrot { var parrot: protocol<IAnimal, IBird>?; func parrotEat() { parrot?.eat(); } func parrotFly() { parrot?.fly(); } } let chinesePeople = ChinesePeople(); chinesePeople.chinesePeople = People(); chinesePeople.peopleEat(); //打印:People eat let parrot = Parrot(); parrot.parrot = Bird(); parrot.parrotEat(); //打印:Bird eat
說明:從UML圖可以看到,遵守接口隔離原則,會使代碼量增加不少,源碼中也是這樣;實際上,IOS在定義協議的時候,可以設置方法為可選實現(optional)和必須實現(默認值),我們可以設置work方法和fly方法為可選實現的方法,這樣在類People和類Bird中,這兩個方法可以根據需要來決定是否實現。采用這種方式,功能上實現是沒有問題,對於簡單的接口來說,也便於維護和管理。但是,當方法隨着業務需求的增加而不斷增加的話,如果我們不應用接口隔離原則,那么就可能形成一個龐大臃腫的接口,這樣的接口的可維護性和重用性是很差的。因此,我們應該盡量細化接口,本篇將一個接口變更為3個專用的接口所采用的就是接口隔離原則。在項目開發中,依賴幾個專用的接口要比依賴一個綜合的接口更加靈活。通過分散定義多個接口,可以預防外來變更的擴散,提高系統的靈活性和可維護性。
雖然接口隔離原則很有意義,但在實際項目中,應該注意度的把握,接口設計的過大或過小都不好,應該根據實際情況多思考再進行設計。