接口隔离原则
定义:
1)客户端不该依赖它不需要的接口;
2)类间的依赖关系应该建立在最小的接口上。
问题由来:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类C来说不是最小接口,则类B和类D必须去实现他们不需要的方法,如下图所示。
解决方案:将臃肿的接口I拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。
举例来说明接口隔离原则:
使用Manager类代表一个管理工人的管理者。有两种类型的工人:普通的和高效的,这两种工人都需要吃午饭。现在来了一批机器人,它们同样为公司工作,但是他们不需要吃午饭。一方面Robot类需要实现IWoker接口,因为他们要工作;另一方面,它们又不需要实现IWorker接口,因为它们不需要吃饭。在这种情况下IWorker就被认为是一个被污染了的接口。
- // interface segregation principle - bad example
- interface IWorker {
- public void work();
- public void eat();
- }
- class Worker implements IWorker {
- public void work() {
- // ....working
- }
- public void eat() {
- // ...... eating in launch break
- }
- }
- class SuperWorker implements IWorker{
- public void work() {
- //.... working much more
- }
- public void eat() {
- //.... eating in launch break
- }
- }
- class Manager {
- IWorker worker;
- public void setWorker(IWorker w) {
- worker=w;
- }
- public void manage() {
- worker.work();
- }
- }
依据接口隔离的原则,我们应该把IWorker接口划分为两个独立的接口,如下面的代码所示。
- //interface segregation principle - good example
- interface IWorkable {
- public void work();
- }
- interface IFeedable{
- public void eat();
- }
- class Worker implements IWorkable, IFeedable {
- public void work() {
- // ....working
- }
- public void eat() {
- //.... eating in launch break
- }
- }
- class SuperWorker implements IWorkable, IFeedable{
- public void work() {
- //.... working much more
- }
- public void eat() {
- //.... eating in launch break
- }
- }
- class Robot implements IWorkable{
- public void work() {
- // ....working
- }
- }
- class Manager {
- IWorkable worker;
- public void setWorker(IWorkable w) {
- worker = w;
- }
- public void manage() {
- worker.work();
- }
- }
这样使用接口隔离原则可以防止庞大、臃肿的接口,这也就接口隔离原则的目的所在。
接口隔离尽量使用多个专门的接口,这和单一职责原则很类似。其实不然,其一,单一职责原则注重的是职责;而接口隔离原则注重对接口依赖的隔离。其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口接口,主要针对抽象,针对程序整体框架的构建。
在依据接口隔离原则拆分接口时,首先必须满足单一职责原则。其次,在使用接口隔离原则时,应做到以下几点:
- 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
- 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
- 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。 那么,在实际应用中,通常一个接口只服务于一个子模块或是业务逻辑;
- 力求通过业务逻辑压缩接口中的“public”方法,让接口“满身筋骨”。
- 已被污染的接口,尽量去修改;若变更太大的话,可以使用适配器模块。