「设计模式」六大原则之四:接口隔离原则小结


「设计模式」六大原则系列链接:
「设计模式」六大原则之一:单一职责小结
「设计模式」六大原则之二:开闭职责小结
「设计模式」六大原则之三:里氏替换原则小结
「设计模式」六大原则之四:接口隔离原则小结
「设计模式」六大原则之五:依赖倒置原则小结
「设计模式」六大原则之六:最小知识原则小结

六大原则体现很多编程的底层逻辑:高内聚、低耦合、面向对象编程、面向接口编程、面向抽象编程,最终实现可读、可复用、可维护性。

设计模式的六大原则有:

  • Single Responsibility Principle:单一职责原则
  • Open Closed Principle:开闭原则
  • Liskov Substitution Principle:里氏替换原则
  • Law of Demeter:迪米特法则(最少知道原则)
  • Interface Segregation Principle:接口隔离原则
  • Dependence Inversion Principle:依赖倒置原则
    把这六个原则的首字母联合起来( L 算做一个)就是 SOLID (solid,稳定的),其代表的含义就是这六个原则结合使用的好处:建立稳定、灵活、健壮的设计。

本文介绍 SOLID 中的第四个原则:接口隔离原则。它对应 SOLID 中的英文字母“I”。

1.接口隔离原则定义

接口隔离原则的英文翻译是“ Interface Segregation Principle”,缩写为 ISP。

Robert Martin 在 SOLID 原则中是这样定义它的:“Clients should not be forced to depend upon interfaces that they do not use。”直译成中文的话就是:客户端不应该被强迫依赖它不需要的接口。

其中的“客户端”,可以理解为接口的调用者或者使用者。

接口隔离的原则的目的是系统解开耦合,从而容易重构。

接口尽量小,功能尽量单一,说白了就是接口粒度要细。

2. 如何理解

“接口”这个名词可以用在很多场合中。生活中我们可以用它来指插座接口等。在软件开发中,我们既可以把它看作一组抽象的约定,也可以具体指系统与系统之间的 API 接口,还可以特指面向对象编程语言中的接口等。

理解接口隔离原则的关键,就是理解其中的“接口”二字。在这条原则中,我们可以把“接口”理解为下面三种东西:

  • 一组 API 接口集合
  • 单个 API 接口或函数
  • OOP 中的接口概念

如果把“接口”理解为一组接口集合,可以是某个微服务的接口,也可以是某个类库的接口等。如果部分接口只被部分调用者使用,我们就需要将这部分接口隔离出来,单独给这部分调用者使用,而不强迫其他调用者也依赖这部分不会被用到的接口。

如果把“接口”理解为单个 API 接口或函数,部分调用者只需要函数中的部分功能,那我们就需要把函数拆分成粒度更细的多个函数,让调用者只依赖它需要的那个细粒度函数。

如果把“接口”理解为 OOP 中的接口,也可以理解为面向对象编程语言中的接口语法。那接口的设计要尽量单一,不要让接口的实现类和调用者,依赖不需要的接口函数。

在具体应用该原则时,可以参考下面几个规则衡量:

  • 接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。
  • 为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。
  • 根据环境和业务不同的标准去考虑。
  • 提高内聚,减少对外交互。让接口用最少的方法完成最多的事情。

分享一张来自 java硕哥 整理的思维导图:
在这里插入图片描述

3. 接口隔离原则与单一职责原则的区别

单一职责原则针对的是模块、类、接口的设计。

接口隔离原则相对于单一职责原则,一方面更侧重于接口的设计,另一方面它的思考角度也是不同的。

接口隔离原则提供了一种判断接口的职责是否单一的标准:通过调用者如何使用接口来间接地判定。

如果调用者只使用部分接口或接口的部分功能,那接口的设计就不够职责单一。

2. 举例说明

实现一个音乐播放器, 定义一个接口:

interface IMusicPlayer {
    
    
    //开始
    void start(); 
    //停止
    void stop();
    //暂停
    void pause();
    //复原
    void resume();
    //获取歌曲时长
    String getSongLength();
}

这里满足了单一职责原则,却不满足接口隔离。

假如我们现在有个歌曲展示器 SongDisplayer,需要展示歌曲时长,那么我们也应该有个 getSongLength() 函数,我们直接实现 IMusicPlayer接口吗,实现这个接口就必须实现里面的start()等方法,但是这些方法肯定不是我需要的,也不是我应该有的,这就是问题,因为接口不够小,不干净,不纯粹,明显违背了接口隔离原则,我们就可以对接口进行拆分:

//音乐播放器就仅限于对播放的控制
interface IMusicPlayer {
    
    
    //开始
    void start(); 
    //停止
    void stop();
    //暂停
    void pause();
    //复原
    void resume();
    ...
}

//歌曲展示器就仅限于对歌曲信息的展示
interface ISongDisplayer {
    
    
    //获取歌曲时长
    String getSongLength();
    //获取歌曲名字
    String getSongName();
    ...
}

当我们实现播放器时 可以同时实现这两个接口即可,只需要展示歌曲信息的话,只需要单独实现 ISongDisplayer即可。

public class MyPlayer implements IMusicPlayer,ISongDisplayer{
    
    
  //……
}

这样实现便更利于维护,也符合我们的接口隔离原则。

4. 小结

接口要尽量小,尽量单一,无关的接口不要冗余。粒度小,更耦合,更灵活,不会伤筋动骨。

参考:

《设计模式之美》

《重学 Java 设计模式》

《Android 源码设计模式解析与实战》

设计模式之基-六大设计原则

猜你喜欢

转载自blog.csdn.net/jun5753/article/details/126877957