Typescript中抽象類與接口詳細對比與應用場景介紹

現現在,TS正在逐漸成爲前端OO編程的不二之選,如下是我在學習過程當中對抽象類和接口作的橫向對比。javascript

1. 抽象類當作父類,被繼承。且抽象類的派生類的構造函數中必須調用super();接口能夠當作「子類」繼承其餘類前端

抽象類派生:java

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. 抽象類與接口都沒法實例化, 類類型接口其實是一種 抽象類型學習

按我的理解,在使用類類型的接口時,類類型的接口其實就至關於抽象類的子集。抽象類中除了能夠像接口那樣只定義不實現外,還能夠部分實現,並且也可使用類型修飾符。this

類類型的接口更多的是當作一種抽象的數據類型使用,此處所說的類型一般是某個類的實例類型。blog

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
}

咱們爲move方法添加abstract標識符,是想讓開發者很是明白,Human的派生類中必需要實現此方法;而使用protected標識符,是想限制move方法調用或重載的權限。

綜合來講抽象類更多的是實現業務上的嚴謹性;接口更多的是制定各類規範,而此規範又分爲不少類規範,就像官方文檔在介紹接口這一節的時候所說的,例如函數型規範、類類型規範、混合規範、索引規範等。

相關文章
相關標籤/搜索