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

简介

单一职责原则倾向于设计视角,接口分离原则倾向于实现视角,两者看起来很是类似,可是在某些方面仍是有所区别的。java

定义

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

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

这时候就须要 ISP 原则出场了,它指导你将接口划分红更小的粒度,使用方只须要实现本身须要的接口便可,而不用继承小胖致使不得不实现小胖交代下来的任务。编码

实践

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

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

设计的接口以下:继承

public interface Book {
    public String isbn();
    public String author();
    public Date publishDate();
    public PublisherInfo publisher();
    public PurchaseInfo purchaseInfo();
    public IdentificationInfo identificationInfo();
}

接口工做良好,很好的支持了网站的运行。但因为业务的变化,网站如今不单单要卖二手书了,还要卖新书。这时只是缺乏了收购信息和鉴定信息,可是新书本质上仍是书,所以咱们直接实现了 Book 接口来卖新书。接口

public abstract class NewBook implements Book {
    public PurchaseInfo purchaseInfo() {
        return null;
    }
    public IdentificationInfo identificationInfo() {
        return null;
    }
}

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

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

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

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)
相关文章
相关标签/搜索