継承と構成

DDD
リリース: 2024-12-27 03:26:09
オリジナル
314 人が閲覧しました

Inheritance vs Composition

まず、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 サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート