簡介物件導向的名詞,以 TypeScript 為例。
介紹各種你會看到的名詞。
Class,類別,一種可以整合邏輯和狀態的單位,例如:
// 類別名稱,貴賓狗
class Poodle {
// 靜態公開屬性,正常的貴賓狗的腿數
public static legs = 4;
// 公開屬性,這個貴賓狗的腿數
public legs: number;
// 私有屬性,這個貴賓狗的能量
private energy: number;
// 建構子
constructor(legs = Poodle.legs, energy = 10) {
this.legs = legs;
this.energy = energy;
}
// 公開函式,貴賓狗呼叫
public shout(): string {
this.shoutCost();
return 'woof';
}
// 公開函式,這隻貴賓狗受傷了嗎
public isInjured() {
return Poodle.legs > this.legs;
}
// 公開函式,這隻貴賓狗是不是累了
public isTired(): boolean {
return this.energy < 5;
}
// 私有函式,當叫了之後會消耗的東西
private shoutCost(): void {
this.energy -= 3;
}
}
接著你可以這樣操作:
// 建構實例,常說 new 一個 instnace
const poodle = new Poodle(3);
// 使用公開函式
console.log(`Is injured? ${poodle.isInjured()}`);
console.log(`Shout: ${poodle.shout()}`);
console.log(`Is tired? ${poodle.isTired()}`);
console.log(`Shout: ${poodle.shout()}`);
console.log(`Is tired? ${poodle.isTired()}`);
// 使用公開屬性
console.log(`Legs should have: ${Poodle.legs}, but get ${poodle.legs}`);
// 以下操作會出錯
poodle.energy;
poodle.shoutCost();
有幾點名詞:
把類別抽象化,例如:
abstract class Dog {
public static legs = 4;
public legs: number;
// 注意這裡從 private 改成 protected
protected energy: number;
constructor(legs = Dog.legs, energy = 10) {
this.legs = legs;
this.energy = energy;
}
public shout(): string {
this.shoutCost();
return 'woof';
}
public isInjured(): boolean {
return Dog.legs > this.legs;
}
// 注意這裡從 private 改成 protected
// 除此之外,把這個函示抽象化,abstract
protected abstract shoutCost(): void;
}
// 貴賓犬
class Poodle extends Dog {
protected shoutCost(): void {
this.energy -= 3;
}
}
// 鬥牛犬
class Bulldog extends Dog {
// 呆呆的狗種,嚎叫會消耗更多體力
protected shoutCost(): void {
this.energy -= 4;
}
}
這裡有幾個新的名詞:
Poodle
或 Bulldog
都去繼承抽象類別 Dog
但是抽象類別不能建構:
// 會出錯
const dog = new Dog();
除了抽象類別,你也可以用介面來把抽象層度拉高:
interface Animal {
legs: number;
isInjured(): boolean;
}
// 注意這裡是用 implements 不是 extends
abstract class Dog implements Animal {}
介面一樣不能建構:
// 會出錯
const animal = new Animal();
這裡再強調一下介面本身沒有實作,介面只是告訴大家:我有這個函式,但其他人怎麼實作的我不知道。以上面的介面為例,所有 Animal
都可以有 isInjured
這個函示,並且他回傳的值必須是 boolean
。
也因此類別必須去「實作」這個介面,以上面的抽象類別 Dog
為例,他就實作了這個函示:
abstract class Dog implements Animal {
public isInjured(): boolean {
// 這裡的程式碼,稱為實作
return Dog.legs > this.legs;
}
}
種類 | 建構 | 實作 | 抽象層度 |
---|---|---|---|
class | O | O | 低 |
abstract class | X | O | 中 |
interface | X | X | 高 |
為什麼要拉高抽象層度?
想像一下朋友打電話給你,問你在幹嘛,你可以有兩種選擇:
抽象之後,就可以延伸很多設計模式(Design Patterns)。
雖然介面和抽象類別不能建構,但是他可以被用作型別(type)。
function influriate(animal: Animal) {
return animal.shout();
}
const poodle = new Poodle();
console.log(influriate(poodle));