## 連載:面向對象葵花寶典:思想、技巧與實踐(33) - ISP原則
**ISP**,Interface?Segregation?Principle,中文翻譯為“**接口隔離原則**”。
和DIP原則一樣,ISP原則也是大名鼎鼎的Martin大師提出來的,他在1996年的C++?Reporter發表“?The?Interface?Segregation?Principle”的文章詳細闡述了ISP原則,并且在他的經典著作《?Agile?Software?Development,?Principles,?Patterns》(中文翻譯為:敏捷軟件開發:原則、模式與實踐)、《Practices,?and?Agile?Principles,?Patterns,?and?Practices?in?C#》(中文翻譯為:敏捷軟件開發:原則、模式與實踐(C#版))中詳細解釋了ISP原則。
?
ISP最原始的定義如下:
“CLIENTS?SHOULD?NOT?BE?FORCED?TO?DEPEND?UPON?INTERFACES?THAT?THEY?DO?NOT?USE.”
翻譯成中文就是“客戶端不應該被強迫去依賴它們并不需要的接口”。
?
單純從字面意思來看,ISP原則是5個原則中最好理解的一個了。但是我們深入思考一下,其實發現也沒有那么簡單。如果你還記得我們前面講的那些原則,你可能會想到一個問題:既然有了SRP,為什么還要ISP?
?
現在我們來回想一下SRP原則,如果類滿足了SRP原則,那么基于這個類提煉的接口不就自然而然的滿足了ISP原則了么?為什么我們還要費神費力的又搞一個ISP原則呢?
?
Martin大師自然不會是吃飽了沒事做,故意整個東東來折騰大家,他在ISP的論文中有這么一句話交代了ISP原則,可惜的是很多人都沒有把這句話貼出來:
The?ISP?acknowledges?that?there?are?objects?that?require?non-cohesive?interfaces;
however?it?suggests?that?clients?should?not?know?about?them?as?a?single?class.?Instead,?clients
should?know?about?abstract?base?classes?that?have?cohesive?interfaces.
翻譯一下:ISP原則承認對象需要非內聚的接口,然而ISP原則建議客戶端不需要知道整個類,只需要知道具有內聚接口的抽象父類即可。
?
也就是說,**ISP應用的場景是某些類不滿足SRP原則,但使用這些類的客戶端(即調用的類)應該根據接口來使用它,而不是直接使用它**。
?
雖然翻譯了一下,但還是比較抽象,給個例子一看就明白了,而且已經有一個很好的例子了,即SRP原則中的“一體機”。
?
在“一體機”的樣例中,雖然“一體機”同時具備“打印、復印、掃描、傳真”的功能,但我們并不會設計一個“一體機”的接口,而是設計4個接口。這樣調用接口的類可以根據自己需要精確使用某個接口,而不是調用一個大而全的接口。
?
具體代碼如下:
ICopier.java
~~~
package com.oo.java.principles.isp;
/**
* 復印機接口
*/
public interface ICopier {
/**
* 復印
* @param paper
*/
void copy(Paper paper);
}
~~~
IFaxMachine.java
~~~
package com.oo.java.principles.isp;
/**
* 傳真機接口
*/
public interface IFaxMachine {
/**
* 傳真
* @param msg
*/
void fax(String msg);
}
~~~
IPrinter.java
~~~
package com.oo.java.principles.isp;
/**
* 打印機接口
*/
public interface IPrinter {
/**
* 打印
* @param doc
*/
void print(Document doc);
}
~~~
IScanner.java
~~~
package com.oo.java.principles.isp;
/**
* 掃描儀接口
*/
public interface IScanner {
/**
* 掃描
* @param paper
*/
void scan(Paper paper);
}
~~~
MultiFuncPrinter.java
~~~
package com.oo.java.principles.isp;
/**
* 多功能打印機(一體機)
* 實現了IFaxMachine(傳真機)、ICopier(復印機)、IPrinter(打印機)、IScanner(掃描儀)4個接口
* 而不是提供一個IMultiFuncPrinter的接口,同時提供以上接口的功能
*
*/
public class MultiFuncPrinter implements IFaxMachine, ICopier, IPrinter, IScanner {
@Override
public void scan(Paper paper) {
// TODO Auto-generated method stub
}
@Override
public void print(Document doc) {
// TODO Auto-generated method stub
}
@Override
public void copy(Paper paper) {
// TODO Auto-generated method stub
}
@Override
public void fax(String msg) {
// TODO Auto-generated method stub
}
}
~~~
People.java
~~~
package com.oo.java.principles.isp;
/**
* 人
*/
public class People {
/**
* 復印操作,copy方法依賴ICopier接口,而不是使用MutiFuncPrinter類
*/
public void copy(ICopier copier, Paper paper){
copier.copy(paper);
}
/**
* 打印操作,print方法依賴IPrinter接口,而不是使用MutiFuncPrinter類
*/
public void print(IPrinter printer, Document doc){
printer.print(doc);
}
/**
* 傳真操作,fax方法依賴IFaxMachine接口,而不是使用MutiFuncPrinter類
*/
public void fax(IFaxMachine faxer, String message){
faxer.fax(message);
}
/**
* 掃描操作,scan方法依賴IScanner接口,而不是使用MutiFuncPrinter類
*/
public void scan(IScanner scanner, Paper paper){
scanner.scan(paper);
}
}
~~~
Tester.java
~~~
package com.oo.java.principles.isp;
public class Tester {
public static void mai(String args[]){
People people = new People();
MultiFuncPrinter mfp = new MultiFuncPrinter();
//如下函數都是使用mfp作為參數,但實際上是使用了MultiFuncPrinter類實現了的不同接口
people.copy(mfp, new Paper()); //使用了MultiFuncPrinter類的ICopier接口,
people.fax(mfp, "I love oo"); //使用了MultiFuncPrinter類的IFaxMachine接口,
people.print(mfp, new Document()); //使用了MultiFuncPrinter類的IPrinter接口,
people.scan(mfp, new Paper()); //使用了MultiFuncPrinter類的IScanner接口,
}
}
~~~
- 前言
- (1) - 程序設計思想的發展
- (2) - 面向對象語言發展歷史
- (3) - 面向過程 vs 面向對象
- (4) - 面向對象是瑞士軍刀還是一把錘子?
- (5) - 面向對象迷思:面向對象導致性能下降?
- (6) - 不要說你懂“類”
- (7) - “對象”新解
- (8) - “接口” 詳解
- (9) - “抽象類” 詳解
- (10) - “抽象” 詳解
- (11) - “封裝” 詳解
- (12) - “繼承” 詳解
- (13) - “多態” 詳解
- (14) - 面向對象開發技術流程
- (15) - 需求詳解
- (16) - 需求分析終極目的
- (17) - 需求分析518方法
- (18) - 用例分析
- (19) - 功能點提取
- (20) - 用例圖的陷阱
- (21) - SSD
- (22) - 領域模型
- (23) - 領域建模三字經
- (24) - 設計模型
- (25) - 類模型
- (26) - 類模型三板斧
- (27) - 動態模型設計
- (28) - 設計原則:內聚&耦合
- (29) - 高內聚低耦合
- (30) - SRP原則
- (31) - OCP原則
- (32) - LSP原則
- (33) - ISP原則
- (34) - DIP原則
- (35) - NOP原則
- (36) - 設計原則如何用?
- (37) - 設計模式:瑞士軍刀 or 錘子?
- (38) - 設計模式之道
- (39) - 設計原則 vs 設計模式
- (40) - DECORATOR模式
- (完)- 書籍已經出版