typescript中抽象類與介面詳細對比與應用場景介紹
現如今,TS正在逐漸成為前端OO程式設計的不二之選,以下是我在學習過程中對抽象類和介面做的橫向對比。
1. 抽象類當做父類,被繼承。且抽象類的派生類的建構函式中必須呼叫super();介面可以當做“子類”繼承其他類
抽象類派生:
abstract class Human { constructor (readonly name:string) {} } class Student extends Human { constructor (name:string) { super(name) } }
介面繼承類:
class Man { job: string; constructor (readonly name: string) {} earnMoney () { console.log(`earning money`) } } interface HumanRule extends Man{ nose: string; mouth: string; ear: string; eye: string; eyebrow: string }
當類被介面繼承時,通常是需要為這個類的子類新增約束。例如下面的例子中,Man類的子類就需要去實現特定的五官屬性,否則將會報錯。
class Player extends Man implements HumanRule{ nose: string; mouth: string; ear: string; eye: string; eyebrow: string constructor (name) { super(name); } }
2. 抽象類與介面都無法例項化, 類型別介面實際上是一種 抽象型別
按個人理解,在使用類型別的介面時,類型別的介面其實就相當於抽象類的子集。抽象類中除了可以像介面那樣只定義不實現外,還可以部分實現,而且也可以使用型別修飾符。
類型別的介面更多的是當做一種抽象的資料型別使用,此處所說的型別通常是某個類的例項型別。
let James: Player = new Player('james');// 類型別使用 class SoccerPlayer extends Player { constructor (name) { super(name) } playSoccer () { console.log(`${this.name} is playing soccer.`) } } function createPlayer (pl: SoccerPlayer, name: string) {// 類型別呼叫 return new SoccerPlayer(name); }
3. 介面中不能包含具體實現,抽象類中除抽象函式之外,其他函式可以包含具體實現
此處我們將Human類增加一些內容:
abstract class Human { constructor (readonly name:string) {} protected thinking () { console.log(`I am a human, so i can think, ${this.name} is thinking.`) } }
作為人類,可以在人類 這個類中新增具體實現,因為人類都可以思考。所以思考這個類就不必非要放到子類中去具體實現,這也正是抽象類的靈活之處。
4. 抽象類中的抽象方法在子類中必須實現, 介面中的非可選項在介面被呼叫時必須實現。
此處我們繼續增加Human類的內容,增加move的具體實現方法為抽象方法,因為不同型別的人,移動的實現不同。(此處實際上也是OO的特性中,多型的一種具體實現)
abstract class Human { constructor (readonly name:string) {} protected thinking () { console.log(`I am a human, so i can think, ${this.name} is thinking.`) } abstract move (): void } class Student extends Human { constructor (name:string) { super(name) } move () { console.log(`I am a student, so i move by bus`) } }
而介面一旦呼叫,就必須要嚴格實現。此處以函式型別的介面為例:
interface createPlayer { (pl: SoccerPlayer, name:string): SoccerPlayer } let createPlayer:createPlayer = function(pl: SoccerPlayer, name: string) {// 修改createPlayer 使用匿名函式方法建立 return new SoccerPlayer(name); }
5. 抽象方法可當做類的例項方法,新增訪問修飾符;但是介面不可以
抽象方法的新增訪問修飾符和介面的嚴格實現其實都是各自的特點,我們也往往是根據這些特點去選擇究竟是使用抽象類還是使用介面。
還拿Human類來說:
abstract class Human { constructor (readonly name:string) {} protected thinking () { console.log(`I am a human, so i can think, ${this.name} is thinking.`) } protected abstract move (): void }