介面隔离原则 Interface Segregation Principles

最後,我们来到了 SOLID 当中的介面隔离原则。这里我们先举先前提到过的 BaseballPlayer and TennisPlayer 的例子。

由於两个类别的运动选手,同样都会击球和跑奔跑,因此我们将这两个方法抽象出来,变成一个 Athlete 介面

interface Athlete {
  hit(): void;
  run(): void;
}

接着,我们让 BaseballPlayer and TennisPlayer 分别去执行这个介面。当然两者各自有自己的实作方式

class BaseballPlayer implements Athlete {
  name: string
  
  constructor(name){
    this.name = name
  }

  hit() {
    console.log(`${this.name} can hit baseball`)
  }
  
  run() {
    console.log(`${this.name} can run`)
  }
}

class TennisPlayer implements Athlete {
  name: string
  
  constructor(name){
    this.name = name
  }

  hit() {
    console.log(`${this.name} can hit tennis`)
  }
  
  run() {
    console.log(`${this.name} can run`)
  }
}

最後,我们可以得到

const jeter = new BaseballPlayer('jeter')
const federer = new TennisPlayer('federer')

jeter.hit()    // jeter can hit baseball
jeter.run()    // jeter can run
federer.hit()  // federer can hit tennis
federer.run()  // federer can run

持续为使用者提供新功能

後来,BaseballPlayer 认为他自己除了会打会跑之外,还要很会投球,因此希望 Athlete 可以加入 pitch 这个方法。

interface Athlete {
  hit(): void;
  run(): void;
  pitch(): void;
}

於是 Athlete 从善如流

class BaseballPlayer implements Athlete {
  name: string
  
  constructor(name){
    this.name = name
  }

  hit() {
    console.log(`${this.name} can hit baseball`)
  }
  
  run() {
    console.log(`${this.name} can run`)
  }
  
  pitch() {
    console.log(`${this.name} can pitch`)
  }
}

BaseballPlayer 也顺利实作出 pitch 方法

const jeter = new BaseballPalyer('jeter')

jeter.pitch()    // jeter can pitch

问题

不过这时候 TennisPlayer 就觉得有点奇怪,因为他认为网球选手不需要会投球。但是因为同样执行了 Athlete,因此需要实作 pitch 方法,所以该怎麽办呢?

於是 TennisPlayer 只好硬着头皮这样实作

class TennisPlayer implements Athlete {
  name: string
  
  constructor(name){
    this.name = name
  }

  hit() {
    console.log(`${this.name} can hit tennis`)
  }
  
  run() {
    console.log(`${this.name} can run`)
  }
  
  pitch() {
    console.log(`Sorry ${this.name} cannot pitch`)
  }
}

然後告诉大家其实网球选手不会投球

const federer = new TennisPlayer('jeter')
federer.pitch()    // Sorry federer cannot pitch

不要强迫使用不需要的功能

这时候,介面隔离原则就说话了:

In the field of software engineering, the interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use.

使用者不应该被强迫依赖不需要的功能。

回到刚刚的例子,就是不应该强迫 TennisPlayer 去执行 Athlete 的 pitch 功能。

但是BaseballPlayer还是需要 pitch 这个功能啊,该怎麽办呢?其实很简单,就把所介面给拆开吧!

interface Athlete {
  hit(): void;
  run(): void;
}

interface Pitch {
  pitch(): void;
}

然後各自执行自己需要的介面。像是 BaseballPlayer 就执行 AthletePitch

class BaseballPlayer implements Athlete, Pitch {
  name: string
  
  constructor(name){
    this.name = name
  }

  hit() {
    console.log(`${this.name} can hit baseball`)
  }
  
  run() {
    console.log(`${this.name} can run`)
  }
  
  pitch() {
    console.log(`${this.name} can pitch`)
  }
}

TennisPlayer 只要执行 Athlete 就行

class TennisPlayer implements Athlete {
  name: string
  
  constructor(name){
    this.name = name
  }

  hit() {
    console.log(`${this.name} can hit tennis`)
  }
  
  run() {
    console.log(`${this.name} can run`)
  }
}

各取所需,打完收工!

小结

「介面隔离原则」同样从使用者的角度出发,不要依赖於完全不需要的功能,以避免未来收到不相关的功能影响。


<<:  前端工程师也能开发全端网页:挑战 30 天用 React 加上 Firebase 打造社群网站|Day30 社群网站上线啦!

>>:  Day18 Loops(Ⅴ)

JQuery 学习纪录 ( 6 )

这次非常久才发布学习纪录,因为最近当兵的关系,能学习的时间又被压缩了,但我还是会努力播出时间练习的。...

【Day7】试着用JSX在页面上渲染出Table吧٩(๑❛ᴗ❛๑)۶

前面在第四篇的时候有稍微说明JSX是什麽东西和有什麽优点, 这一篇我们要来试着使用JSX 在Reac...

Day08 - 试用 material color tool 哦

之前就一直觉得网页配色好难,今天试用了 material color tool,觉得之後设计网页可以...

【Day13】数据展示元件 - Accordion/Collapse 摺叠面板

元件介绍 Accordion 是一个可折叠/展开内容区域的元件。主要是针对显示内容复杂或很多的页面进...

[Day5] Web 小幸福

[Day5] Web 小幸福 今天我回彰化阿嬷家 看到绿油油的稻田,骑脚踏车凉风吹拂以及蝉鸣声叽叽叫...