In object-oriented programming, inheritance is the mechanism of basing an object or class upon another object (prototype-based inheritance) or class (class-based inheritance), retaining similar implementation. Also defined as deriving new classes (sub classes) from existing ones such as super class or base class and then forming them into a hierarchy of classes.
在物件導向程式語言當中,「繼承」是一種機制,可以保留某個類別或物件的實作方法。奠基在既有類別上創立一個新的類別,並建立階層的關係。
In most class-based object-oriented languages, an object created through inheritance, a "child object", acquires all the properties and behaviors of the "parent object"
...
Inheritance allows programmers to create classes that are built upon existing classes, to specify a new implementation while maintaining the same behaviors (realizing an interface), to reuse code and to independently extend original software via public classes and interfaces. The relationships of objects or classes through inheritance give rise to a directed graph.
child 物件繼承 parent 物件時,可以
拿先前提到的例子來看,並做一些延伸如下:
class BaseballPlayer {
name: string
constructor(name: string) {
this.name = name
}
hit() {
console.log(`${this.name} can hit`)
}
run() {
console.log(`${this.name} can run`)
}
}
class Shortstop extends BaseballPlayer {
run() {
console.log(`${this.name} can run very fast`)
}
defense() {
console.log(`${this.name} can defense`)
}
}
const jeter = new Shortstop('jeter')
jeter.name // jeter
jeter.hit() // jeter can hit
jeter.defense() // jeter can can defense
jeter.run() // jeter can run very fast
可以看到
Shortstop
類別繼承了 BaseballPlayer
類別Shortstop
類別的實例 jeter
,擁有其 parent 類別的
name
屬性hit
方法,並維持同樣的實作方式run
方法,但使用了新的實作方式Shortstop
類別的實例 jeter
擁有新的 defense
方法其實「抽象」和「繼承」是一體兩面。當我們不斷的將「許多類別」的共同特質抽出、變成更高一層的 parent 類別的時候(抽象),這時候「許多類別」就是繼承了這個 parent 類別,也就是繼承了這個共同特質。
在能夠繼承的情況下,因為可以直接使用 parent 類別、parent's parent 類別 ... 等的屬性和方法,因此 child 類別來說,可以不需要重複撰寫同樣的程式碼。另一方面,「繼承」也建立了物件之間彼此的階層關係,讓我們能夠更快速的模擬真實世界事物的關係。
雖然「繼承」看起還有許多好處,不過「繼承」的缺點是,parent 類別和 child 類別有高度的關聯性,換個角度來說,就是難以根據新的需求或變化進行擴充。
譬如「人」這個類別只會在地上跑,不會在天上飛。如果今天我們想要建立一個超人的實例,那麼究竟是要讓「超人」類別去繼承「人」呢,還是繼承「鳥」類別呢?在這樣的情況下,先前所提到過抽象了另外一種實現方式「介面」就可以派上用場了!
class Human {
name: string
constructor(name: string) {
this.name = name
}
run(): void {
console.log(`${this.name} can run`)
}
}
interface Fly {
fly(): void;
}
class Superman extends Human implements Fly {
fly(): void {
console.log(`${this.name} can fly`)
}
}
const clark = new Superman('clark')
clark.run() // clark can run
clark.fly() // clark can fly