## 连载:面向对象葵花宝典:思想、技巧与实践(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模式
- (完)- 书籍已经出版