まず、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()
プログラムが成長するにつれて独自の重要性を持つ別のエンティティを導入する必要があるため、これはかなり脆弱に見えます。このアンチパターンは、一般に神オブジェクトと呼ばれています。したがって、OOP の問題は、エンティティを作成するときに意味があり、後で要件の変化に応じて変更できることです。これらの変更により、クラスの階層構造が崩れる可能性があります。
再利用性の欠如は関数型言語ではなくオブジェクト指向言語にあると思います。なぜなら、オブジェクト指向言語の問題は、暗黙的な環境をすべて持ち歩くことだからです。あなたはバナナが欲しかったのですが、手に入れたのはバナナとジャングル全体を抱えたゴリラでした。
-- Joe Armstrong (Erlang の作成者)
物事が何であるかを考えるのではなく、物事が何をするのかに移りましょう。
これらのメソッドをクラスに緊密に結合する代わりに、それらを関数として保持し、必要なときにいつでも一緒に構成することができます。素晴らしい!しかし、では特定のインスタンスをどのように操作すればよいのでしょうか?さて、インスタンスを関数に直接渡します。 Closure により、関数は渡された状態 (インスタンス) を記憶できます。
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 中国語 Web サイトの他の関連記事を参照してください。