前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计原则之接口分离原则(ISP)

设计原则之接口分离原则(ISP)

作者头像
Dylan Liu
发布2019-07-01 14:01:36
1.2K0
发布2019-07-01 14:01:36
举报
文章被收录于专栏:dylanliudylanliu

简介

单一职责原则倾向于设计视角,接口分离原则倾向于实现视角,二者看起来非常相似,但是在某些方面还是有所区别的。

定义

接口分离原则(Interface Segregation Principle):使用方不应该依赖于它不使用的方法(no client should be forced to depend on methods it does not use.)。

ISP 原则是用来处理胖接口或胖基类的,接口或类中包含了茫茫多的方法就称为胖接口或胖基类(简称小胖吧)。使用方在使用小胖的时候,会发现自己没有必要实现某个方法,但由于在小胖中存在,自己不得不实现一个,要么是空方法,要么抛出异常以表明自己不支持。

这时候就需要 ISP 原则出场了,它指导你将接口划分成更小的粒度,使用方只需要实现自己需要的接口即可,而不用继承小胖导致不得不实现小胖交代下来的任务。

实践

设计原则只里氏替换原则中,我们举的例子就违反了接口分离原则,这里再举一个例子说明这个原则。

需求要求我们做一个二手书设计,要求我们记录书的基本信息,收购的基本信息,以及二手书的鉴定信息等信息。

设计的接口如下:

代码语言:javascript
复制
public interface Book {
    public String isbn();
    public String author();
    public Date publishDate();
    public PublisherInfo publisher();
    public PurchaseInfo purchaseInfo();
    public IdentificationInfo identificationInfo();
}

接口工作良好,很好的支持了网站的运行。但由于业务的变化,网站现在不仅仅要卖二手书了,还要卖新书。这时只是缺少了收购信息和鉴定信息,但是新书本质上还是书,因此我们直接实现了 Book 接口来卖新书。

代码语言:javascript
复制
public abstract class NewBook implements Book {
    public PurchaseInfo purchaseInfo() {
        return null;
    }
    public IdentificationInfo identificationInfo() {
        return null;
    }
}

所有的新书都使用 NewBook 接口,改动也很小就支持了新书的销售,很美好。

这个设计就违反了 ISP 原则,Book 强制所有的书都必须有收购信息和鉴定信息,但新书却并没有这两项,将新书实现 Book 接口强制新书也必须要有这两项信息,无奈只能使用折中办法返回null。

要改变这种情况,我们需要将收购信息和鉴定信息单独拆到一个接口中,二手书的实现继承这个接口,而新书的实现不继承这两个接口。

代码语言:javascript
复制
public interface Book {
    public String isbn();
    public String author();
    public Date publishDate();
    public PublisherInfo publisher();
    public PurchaseInfo purchaseInfo();
    public IdentificationInfo identificationInfo();
}

public interface SecondHand {
    public PurchaseInfo purchaseInfo();
    public IdentificationInfo identificationInfo();
}

接口拆分成这样已经满足网站的要求了,如果后面网站发展越来越大,鉴定成本不可承受时,有些书籍不作鉴定直接入库,这时我们就需要将 SecondHand 接口再拆分成两个接口,将收购信息和鉴定信息分离开来,不作耦和。

与 SRP 的比较

SRP 原则说的是一个类只能有一个改变的理由,ISP 原则指的是使用方不应该依赖它不使用的方法。有的设计符合 SRP 原则却并不符合 ISP 原则。

举一个例子,正常的 Stack 都有 push pop 方法,如果使用方有一个使用场景,只能使用 push, 不能使用 pop, 那么使用方就不能继承 Stack 来实现自己的功能,与 ISP 原则相悖。但是原始的 Stack 设计是完全符合 SRP 原则的,pushpop 就是它自己的职责。

从这个例子可以看出,ISP 原则不仅仅能指导我们分离接口,还能帮助判断一个类的继承是不是合理的。

可能有的人觉得这个例子牵强,谁会限制一个 Stack 不能有 pop 方法。大家可以去看下Java 中的 Stack 实现,它继承了Vector ,而 Vector 是一个 ListStack 应该只能压入弹出的,但是却继承了 Listadd,remove,get 等方法,是一个很糟糕的实现设计。

总结

接口分离原则与单一职责原则挺相近,但在某些点上是有区别的。日常编码实现某个接口、继承某个类时,问问自己,这样符合 ISP 原则么?

Reference

  1. Interface segregation principle
  2. Understand Single Responsibility and Interface Seg
  3. In SOLID, what is the distinction between SRP and ISP? (Single Responsibility Principle and Interface Segregation Principle)
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义
  • 实践
  • 与 SRP 的比较
  • 总结
  • Reference
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档