在 TypeScript 中,繼承和多型是兩個重要的面向對象編程 (OOP) 概念,這些特性使程式碼具有更高的重用性和靈活性。透過繼承,我們可以建立新的類別來擴展或覆寫父類別的功能,而多型則允許我們在不同的類別中使用相同的方法介面,實現動態行為。
繼承是指一個類別可以從另一個類別繼承屬性和方法。這讓我們能夠基於現有類別進行擴展,避免重複撰寫相同的程式碼。繼承的類別稱為子類別 (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
關鍵字用來呼叫父類別的建構函式,確保父類別的屬性被正確初始化。
多型是指不同的類別可以共享相同的方法名稱,但其實作的行為會依據具體的類別而不同。這允許我們以一致的方式處理不同型別的物件,而不需要知道具體的物件類型。
在 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.
在這個延伸範例裡可以看到,Cat
和 Dog
類別都繼承了 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
父類別,並讓各種具體角色如 Ironman
或 Mario
繼承並實作自己的行為。
而在網頁開發中,我們則可能會處理不同的表單元素如按鈕、輸入框等,這些元素可能有相似的行為如渲染、點擊事件等。透過繼承和多型,我們可以以統一的方式處理這些不同的表單元素。
TypeScript 的繼承和多型提供了強大的面向對象設計能力,讓我們可以使用既有的類別來建立複雜且靈活的程式架構。透過繼承,我們可以重用既有的邏輯;而透過多型,我們能夠讓程式碼更具動態性和彈性。這兩個概念的結合大大提高了程式的可擴展性和可維護性,是開發大型應用程式時不可或缺的工具。