以下内容来自《Java设计模式》
1 接口隔离原则
接口隔离原则定义如下:
接口隔离原则(Interface Segregation Principle, ISP)
:使用多个专门的接口,而不使用单一 的总接口,即客户端不应该依赖那些它不需要的接口。
根据接口隔离原则,当一个接口太大时,我们需要将它分割成一些更细小的接口,使用该接 口的客户端仅需知道与之相关的方法即可。每一个接口应该承担一种相对独立的角色,不干 不该干的事,该干的事都要干。这里的“接口”往往有两种不同的含义:一种是指一个类型所具 有的方法特征的集合,仅仅是一种逻辑上的抽象;另外一种是指某种语言具体的“接口”定义, 有严格的定义和结构,比如Java语言中的interface。对于这两种不同的含义,ISP的表达方式以 及含义都有所不同:
-
当把“接口”理解成一个类型所提供的所有方法特征的集合的时候,这就是一种逻辑上的概 念,接口的划分将直接带来类型的划分。可以把接口理解成角色,一个接口只能代表一个角 色,每个角色都有它特定的一个接口,此时,这个原则可以叫做“角色隔离原则”。
-
如果把“接口”理解成狭义的特定语言的接口,那么ISP表达的意思是指接口仅仅提供客户端 需要的行为,客户端不需要的行为则隐藏起来,应当为客户端提供尽可能小的单独的接口, 而不要提供大的总接口。在面向对象编程语言中,实现一个接口就需要实现该接口中定义的 所有方法,因此大的总接口使用起来不一定很方便,为了使接口的职责单一,需要将大接口 中的方法根据其职责不同分别放在不同的小接口中,以确保每个接口使用起来都较为方便, 并都承担某一单一角色。接口应该尽量细化,同时接口中的方法应该尽量少,每个接口中只 包含一个客户端(如子模块或业务逻辑类)所需的方法即可,这种机制也称为“定制服务”,即 为不同的客户端提供宽窄不同的接口。
2 案例分析
下面通过一个简单实例来加深对接口隔离原则的理解:
Sunny软件公司开发人员针对某CRM系统的客户数据显示模块设计了如图1所示接口,其中方 法dataRead()用于从文件中读取数据,方法transformToXML()用于将数据转换成XML格式,方 法createChart()用于创建图表,方法displayChart()用于显示图表,方法createReport()用于创建文 字报表,方法displayReport()用于显示文字报表。
初始设计方案结构图
在实际使用过程中发现该接口很不灵活,例如如果一个具体的数据显示类无须进行数据转换 (源文件本身就是XML格式),但由于实现了该接口,将不得不实现其中声明的transformToXML()方法(至少需要提供一个空实现);如果需要创建和显示图表,除了需实现 与图表相关的方法外,还需要实现创建和显示文字报表的方法,否则程序编译时将报错。
现使用接口隔离原则对其进行重构。
在图1中,由于在接口CustomerDataDisplay中定义了太多方法,即该接口承担了太多职责,一 方面导致该接口的实现类很庞大,在不同的实现类中都不得不实现接口中定义的所有方法, 灵活性较差,如果出现大量的空方法,将导致系统中产生大量的无用代码,影响代码质量; 另一方面由于客户端针对大接口编程,将在一定程序上破坏程序的封装性,客户端看到了不 应该看到的方法,没有为客户端定制接口。因此需要将该接口按照接口隔离原则和单一职责 原则进行重构,将其中的一些方法封装在不同的小接口中,确保每一个接口使用起来都较为 方便,并都承担某一单一角色,每个接口中只包含一个客户端(如模块或类)所需的方法即 可。
通过使用接口隔离原则,本实例重构后的结构如图2所示:
重构后结构图在使用接口隔离原则时,我们需要注意控制接口的粒度,接口不能太小,如果太小会导致系 统中接口泛滥,不利于维护;接口也不能太大,太大的接口将违背接口隔离原则,灵活性较 差,使用起来很不方便。一般而言,接口中仅包含为某一类用户定制的方法即可,不应该强 迫客户依赖于那些它们不用的方法。
3 设计模式的七大原则
【设计模式】单一职责原则
【设计模式】开闭原则
【设计模式】里氏替换原则
【设计模式】依赖倒转原则
【设计模式】接口隔离原则
【设计模式】合成复用原则
【设计模式】迪米特法则
网友评论