Maison > interface Web > js tutoriel > Héritage vs composition

Héritage vs composition

DDD
Libérer: 2024-12-27 03:26:09
original
314 Les gens l'ont consulté

Inheritance vs Composition

Regardons d'abord un exemple de la façon dont nous obtiendrions l'héritage dans 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
    }
}
Copier après la connexion

On peut visualiser la hiérarchie comme ceci :

Animal
    name
    energy
    eat()
    sleep()
    play()

    Dog
        breed
        bark()

    Cat
        declawed
        meow()
Copier après la connexion

Disons que plus tard, vous êtes chargé d'ajouter une autre entité au système : l'utilisateur.

User
    email
    username
    pets
    friends
    adopt()
    befriend()

Animal
    name
    energy
    eat()
    sleep()
    play()

    Dog
        breed
        bark()

    Cat
        declawed
        meow()
Copier après la connexion

Tout fonctionne bien jusqu'à présent. Cependant, votre chef de projet vous demande désormais d'ajouter également la possibilité de manger, dormir et jouer à l'utilisateur. Comment feriez-vous? Voici comment nous aborderions cela en POO :

Mammal
    name
    eat()
    sleep()
    play()

    User
        email
        username
        pets
        friends
        adopt()
        befriend()

    Animal
        energy

        Dog
            breed
            bark()

        Cat
            declawed
            meow()
Copier après la connexion

Cela semble assez fragile car une autre entité a dû être introduite qui aura désormais sa propre signification à mesure que le programme se développera. Cet anti-modèle est communément appelé Dieu Objet. Par conséquent, le problème avec la POO est que les entités ont une signification lorsque vous les écrivez, qui peut être modifiée ultérieurement à mesure que les exigences changent. Ces changements peuvent effondrer la structure hiérarchique des classes.

Je pense que le manque de réutilisabilité vient des langages orientés objet, pas des langages fonctionnels. Parce que le problème avec les langages orientés objet est qu'ils ont tout cet environnement implicite qu'ils emportent avec eux. Vous vouliez une banane mais ce que vous avez obtenu, c'est un gorille tenant la banane et toute la jungle.
-- Joe Armstrong (Créateur d'Erlang)

Plutôt que de penser à ce que sont les choses, passons à ce que font les choses.

  • Un chien est un dormeur, un mangeur, un joueur et un aboyeur.
  • Un chat est un dormeur, un mangeur, un joueur et un miaou.

Au lieu d'avoir ces méthodes étroitement couplées à une classe, nous pouvons les avoir sous forme de fonctions et les composer ensemble quand nous en avons besoin. Super! Mais alors, comment opérer sur une instance spécifique ? Eh bien, nous transmettons l'instance directement à nos fonctions. La fermeture permet aux fonctions de se souvenir de l'état (instance) qui a été transmis.

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
    }
})
Copier après la connexion

Exemple de chien dormant, mangeur, joueur et aboyeur :

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()
Copier après la connexion

Désormais, les utilisateurs peuvent également manger, dormir et jouer :

function User(email, username) {
    let user = {
        email,
        username,
        pets: [],
        friends: []
    }

    return Object.assign(
        user,
        eater(user),
        sleeper(user),
        player(user)
    )
}
Copier après la connexion

Félicitations, vous vous êtes libéré des structures successorales étroitement liées.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal