超拼科技接口隔离原则 (ISP)详解
当我们设计一个应用程序时,我们应该注意我们将如何抽象一个包含多个子模块的模块。考虑到类实现的模块,我们可以在接口中完成系统的抽象。但是如果我们想扩展我们的应用程序,添加一个只包含原始系统的一些子模块的模块,我们就不得不实现完整的接口并编写一些虚拟方法。这样的接口称为胖接口或污染接口。界面污染不是一个好的解决方案,可能会导致系统出现不适当的行为。
接口隔离原则指出不应强迫客户端实现他们不使用的接口。代替一个胖接口,许多基于方法组的小接口是首选的,每个接口服务一个子模块。
例子
面是一个违反接口隔离原则的例子。我们有一个 Manager 类,它代表管理工人的人。我们有两种类型的工人,一些是普通工人,一些是非常高效的工人。两种类型的工人都工作,他们需要每天休息时间吃饭。但是现在一些机器人进入了他们工作的公司,但他们不吃东西,所以他们不需要发射休息。一方面,新的 Robot 类需要实现 IWorker 接口,因为 robots 可以工作。另一方面,他们不必实施它,因为他们不吃东西。
这就是为什么在这种情况下 IWorker 被认为是污染接口。
如果我们保持目前的设计,新的 Robot 类将被迫实现eat 方法。我们可以编写一个什么都不做的虚拟类(假设每天有 1 秒的启动中断),并且可能对应用程序产生不良影响(例如,经理看到的报告会报告吃的午餐比人数多)。
根据接口隔离原则,灵活的设计不会有污染的接口。在我们的例子中,IWorker 接口应该分成 2 个不同的接口。
// 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 接口拆分为 2 个不同的接口,新的 Robot 类不再被迫实现 eat 方法。此外,如果我们需要机器人的其他功能,例如充电,我们将创建另一个接口 IRechargeble 并使用方法重新充电。
// interface segregation principle - good example
interface IWorker extends Feedable, Workable {
}
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 Robot implements IWorkable{
public void work() {
// ....working
}
}
class SuperWorker implements IWorkable, IFeedable{
public void work() {
//.... working much more
}
public void eat() {
//.... eating in launch break
}
}
class Manager {
Workable worker;
public void setWorker(Workable w) {
worker=w;
}
public void manage() {
worker.work();
}
}
结论
如果设计已经完成,胖接口可以使用适配器模式进行隔离。
像每个原则一样,接口隔离原则是一项原则,需要在设计时花费额外的时间和精力来应用它并增加代码的复杂性。但它产生了灵活的设计。如果我们要应用它超出必要的范围,它将导致代码包含许多具有单一方法的接口,因此应根据经验和常识来确定代码扩展更可能发生的区域未来。