最後,我们来到了 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
就执行 Athlete
和 Pitch
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 社群网站上线啦!
这次非常久才发布学习纪录,因为最近当兵的关系,能学习的时间又被压缩了,但我还是会努力播出时间练习的。...
前面在第四篇的时候有稍微说明JSX是什麽东西和有什麽优点, 这一篇我们要来试着使用JSX 在Reac...
之前就一直觉得网页配色好难,今天试用了 material color tool,觉得之後设计网页可以...
元件介绍 Accordion 是一个可折叠/展开内容区域的元件。主要是针对显示内容复杂或很多的页面进...
[Day5] Web 小幸福 今天我回彰化阿嬷家 看到绿油油的稻田,骑脚踏车凉风吹拂以及蝉鸣声叽叽叫...