讓我們先來看一個如何在 ES5 中實作繼承的範例
class Animal { constructor(name, energy) { this.name = name this.energy = energy } eat(amount) { console.log(`${this.name} is eating.`) this.energy += amount } sleep(length) { console.log(`${this.name} is sleeping.`) this.energy += length } play(length) { console.log(`${this.name} is playing.`) this.energy -= length } } class Dog extends Animal { constructor(name, energy, breed) { super(name, energy) this.breed = breed } bark() { console.log('Woof Woof!') this.energy -= .1 } } class Cat extends Animal { constructor(name, energy, declawed) { super(name, energy) this.declawed = declawed } meow() { console.log('Meow!') this.energy -= .1 } }
我們可以像這樣視覺化層次結構:
Animal name energy eat() sleep() play() Dog breed bark() Cat declawed meow()
稍後,您的任務是為系統新增另一個實體:使用者。
User email username pets friends adopt() befriend() Animal name energy eat() sleep() play() Dog breed bark() Cat declawed meow()
到目前為止一切都很好。然而,您的專案經理現在告訴您也為使用者添加吃飯、睡覺和玩耍的功能。你會怎麼做?以下是我們在 OOP 中解決這個問題的方法:
Mammal name eat() sleep() play() User email username pets friends adopt() befriend() Animal energy Dog breed bark() Cat declawed meow()
這看起來非常脆弱,因為必須引入另一個實體,隨著程式的發展,它現在將具有自己的重要性。這種反模式通常被稱為「God Object」。因此,OOP 的問題在於,實體在編寫時具有含義,並且可以在以後隨著需求的變化而更改。這些變更可能會破壞類別層次結構。
我認為缺乏可重複使用性來自於物件導向的語言,而不是函數式語言。因為物件導向語言的問題是它們帶有所有這些隱式環境。你想要一根香蕉,但你得到的是一隻拿著香蕉的大猩猩和整個叢林。
——喬·阿姆斯壯(Erlang 的創建者)
與其思考事物是什麼,不如讓我們轉向事物的作用。
我們可以將它們作為函數並在需要時將它們組合在一起,而不是將這些方法與類別緊密耦合。偉大的!那我們要如何對具體的實例進行操作呢?好吧,我們將實例直接傳遞給我們的函數。閉包讓函數記住傳遞的狀態(實例)。
const eater = (state) => ({ eat(amount) { console.log(`${state.name} is eating.`) state.energy += amount } }) const sleeper = (state) => ({ sleep(length) { console.log(`${state.name} is sleeping.`) state.energy += length } }) const player = (state) => ({ play(length) { console.log(`${state.name} is eating.`) state.energy -= length } }) const barker = (state) => ({ bark(length) { console.log(`Woof Woof!`) state.energy -= .1 } }) const meower = (state) => ({ meow(length) { console.log(`Meow!`) state.energy -= .1 } })
狗作為睡眠者、食者、玩家和吠叫者的例子:
function Dog(name, energy, breed) { let dog = { name, energy, breed } return Object.assign( dog, eater(dog), sleeper(dog), player(dog), barker(dog) ) } const dog = Dog('Dog', 10, 'Bulldog') dog.eat(10) dog.bark()
現在使用者還可以吃飯、睡覺、玩耍:
function User(email, username) { let user = { email, username, pets: [], friends: [] } return Object.assign( user, eater(user), sleeper(user), player(user) ) }
恭喜,您已經將自己從緊密耦合的繼承結構中解放出來。
以上是繼承與組合的詳細內容。更多資訊請關注PHP中文網其他相關文章!