iT邦幫忙

2024 iThome 鐵人賽

DAY 14
0
JavaScript

用 TypeScript 重新定義前端開發:30 天的實踐與思考系列 第 14

Day14:TypeScript 的繼承與多型 (Inheritance and Polymorphism)

  • 分享至 

  • xImage
  •  

在 TypeScript 中,繼承和多型是兩個重要的面向對象編程 (OOP) 概念,這些特性使程式碼具有更高的重用性和靈活性。透過繼承,我們可以建立新的類別來擴展或覆寫父類別的功能,而多型則允許我們在不同的類別中使用相同的方法介面,實現動態行為。

一、繼承 (Inheritance)

繼承是指一個類別可以從另一個類別繼承屬性和方法。這讓我們能夠基於現有類別進行擴展,避免重複撰寫相同的程式碼。繼承的類別稱為子類別 (Subclass) 或派生類別 (Derived Class),而被繼承的類別稱為父類別 (Superclass) 或基礎類別 (Base Class)。

在 TypeScript 裡,可以使用 extends 關鍵字來實現繼承:

// 定義父類別
class Animal {
    species: string;

    constructor(species: string) {
        this.species = species;
    }

    makeSound(): string {
        return `${this.species} makes a sound.`;
    }
}

// 定義子類別
class Cat extends Animal {
    constructor() {
        super("Cat");
    }

    makeSound(): string {
        return `${this.species} meows.`;
    }
}

const dog = new Cat();
console.log(dog.makeSound()); // Cat meows.

在這個例子裡可以看到程式碼區塊的子類別定義,Cat 類別繼承了 Animal 類別,並且覆寫了 makeSound 方法。而 super 關鍵字用來呼叫父類別的建構函式,確保父類別的屬性被正確初始化。

二、多型 (Polymorphism)

多型是指不同的類別可以共享相同的方法名稱,但其實作的行為會依據具體的類別而不同。這允許我們以一致的方式處理不同型別的物件,而不需要知道具體的物件類型。

在 TypeScript 裡,透過繼承實現多型,子類別可以覆寫父類別的方法,並且可以根據具體的需求實現不同的行為。

同樣以 Animal 來做延伸範例:

// 定義父類別
class Animal {
    species: string;

    constructor(species: string) {
        this.species = species;
    }

    makeSound(): string {
        return `${this.species} makes a sound.`;
    }
}

// 定義子類別 Cat
class Cat extends Animal {
    constructor() {
        super("Cat");
    }

    makeSound(): string {
        return `${this.species} meows.`;
    }
}

// 定義子類別 Dog
class Dog extends Animal {
    constructor() {
        super("Dog");
    }

    makeSound(): string {
        return `${this.species} barks.`;
    }
}

// 使用多型處理不同的類別
function getAnimalSound(animal: Animal): string {
    return animal.makeSound();
}

const cat = new Cat();
const dog = new Dog();

console.log(getAnimalSound(cat)); // Cat meows.
console.log(getAnimalSound(dog)); // Dog barks.

在這個延伸範例裡可以看到,CatDog 類別都繼承了 Animal 類別,但它們各自覆寫了 makeSound 方法。getAnimalSound 函式接受一個 Animal 類別的物件作為參數,並依據具體類別來執行不同的 makeSound 行為。這就是多型的核心—同一個介面 (interface),不同的實作

三、抽象類別與多型

除了基本的類別繼承和多型之外,TypeScript 還支援抽象類別來進一步實現多型。抽象類別允許我們定義一些通用的行為,但強制子類別實現特定的抽象方法。

將上面的 Animal 再延伸為使用抽象類別後:

// 定義抽象類別
abstract class Animal {
    species: string;

    constructor(species: string) {
        this.species = species;
    }

    // 抽象方法-需要被子類別各自實作
    abstract makeSound(): string; 

    // 具體方法-可以被子類別共享
    move(): string {
        return `${this.species} is moving.`;
    } 
}

// 定義子類別 Cat
class Cat extends Animal {
    constructor() {
        super("Cat");
    }

    makeSound(): string {
        return `${this.species} meows.`;
    }
}

// 定義子類別 Dog
class Dog extends Animal {
    constructor() {
        super("Dog");
    }

    makeSound(): string {
        return `${this.species} barks.`;
    }
}

const cat = new Cat();
const dog = new Dog();

console.log(cat.makeSound()); // Cat meows.(各自實作)
console.log(dog.makeSound()); // Dog barks.(各自實作)
console.log(cat.move());      // Cat is moving.(共享)
console.log(dog.move());      // Dog is moving.(共享)

在這個例子中,Animal 是一個抽象類別,並包含一個抽象方法 makeSound,這個方法強制要求所有繼承自 Animal 的子類別都必須提供自己的實作。此外,Animal 類別也可以包含具體方法,如 move 方法,這可以被所有子類別共享。

四、繼承與多型的應用場景

在實際開發與應用時,繼承和多型的結合非常適合用來處理多種類型的物件,尤其是當我們需要對多種類型的物件執行相似的操作時。例如:

在遊戲開發中,我們可能有多種不同的遊戲角色類型,但每個角色都會有共同的行為,如移動、攻擊等。透過繼承,我們可以定義一個 Character 父類別,並讓各種具體角色如 IronmanMario 繼承並實作自己的行為。
而在網頁開發中,我們則可能會處理不同的表單元素如按鈕、輸入框等,這些元素可能有相似的行為如渲染、點擊事件等。透過繼承和多型,我們可以以統一的方式處理這些不同的表單元素。

結語

TypeScript 的繼承和多型提供了強大的面向對象設計能力,讓我們可以使用既有的類別來建立複雜且靈活的程式架構。透過繼承,我們可以重用既有的邏輯;而透過多型,我們能夠讓程式碼更具動態性和彈性。這兩個概念的結合大大提高了程式的可擴展性和可維護性,是開發大型應用程式時不可或缺的工具。


上一篇
Day13:TypeScript 的類別(Classes)基礎
下一篇
Day15:TypeScript 的模組系統 (Modules)
系列文
用 TypeScript 重新定義前端開發:30 天的實踐與思考30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言