Maison > Java > javaDidacticiel > le corps du texte

Application du \'Principe de substitution de Liskov\' avec Typescript et Java

PHPz
Libérer: 2024-08-30 06:01:32
original
794 Les gens l'ont consulté

Aplicando o

Concepts

Interfaces

Une interface définit un contrat ou un ensemble de méthodes et de propriétés qu'une classe doit implémenter. Les interfaces sont utilisées pour garantir qu'une classe suit un certain format, mais elles ne fournissent pas d'implémentation de méthodes, uniquement leurs signatures.

Chaque fois qu'une classe implémente une interface, elle signe tous les contrats (méthodes et attributs) pour l'interface. Chaque attribut et méthode est obligatoirement implémenté.

SOLIDE

SOLID est un acronyme qui représente cinq principes fondamentaux de la programmation orientée objet, proposés par Robert C. Martin - Oncle Bob. Ici vous pouvez en savoir plus sur son article.
Ces principes visent à améliorer la structure et la maintenance du code, le rendant plus flexible, évolutif et plus facile à comprendre. De tels principes aident le programmeur à créer des codes plus organisés, en répartissant les responsabilités, en réduisant les dépendances, en simplifiant le processus de refactorisation et en favorisant la réutilisation du code.

À propos de LSP

Le « L » dans l'acronyme signifie « Principe de substitution de Liskov ». La phrase utilisée par Oncle Bob pour définir ce principe était :

"Les classes dérivées doivent pouvoir remplacer entièrement les classes de base"

Il est donc suggéré que la classe dérivée soit la plus proche possible de la classe de base, afin que la classe dérivée puisse remplacer sa classe de base sans aucune modification dans le code.

Ce principe a été introduit par Barbara Liskov en 1988, basé sur la théorie de l'abstraction et des types de données. Dérivé du concept de Design by Contracts (DBC), popularisé par Bertrand Meyer en 1986.

Une autre spécification de ce principe est :

Le sous-type doit être utilisé comme type de base sans aucune surprise.

En programmation, les changements et les surprises peuvent causer des problèmes. Si une fonctionnalité du système doit être remplacée, la nouvelle doit fournir le même type d'informations, sinon le système risque de tomber en panne. Pour garantir que la classe S a le même comportement que la classe de base T, il est indispensable d'utiliser un contrat (interface ou classe abstraite) qui définit les méthodes obligatoires d'implémentation de la nouvelle fonctionnalité, afin de garantir l'intégrité de la similarité entre la classe S et classe T.

Application pratique

Considérez une classe de base Bird avec une méthode fly() qui sera utilisée dans deux classes enfants : Sparrow et Ostrich.

Fichier : bird.java

class Bird {
    void fly() {
        System.out.println("I can fly!");
    }
}

class Sparrow extends Bird {
    // Herda o comportamento de 'fly' da classe 'Bird'
}

class Ostrich extends Bird {
    @Override
    void fly() {
        throw new UnsupportedOperationException("I cannot fly");
    }
}
Copier après la connexion

Fichier : bird.ts

class Bird {
  fly() {
    console.log("I can fly!");
  }
}

class Sparrow extends Bird {}

class Ostrich extends Bird {
  fly() {
    throw new Error("I cannot fly");
  }
}
Copier après la connexion

Problèmes rencontrés

Ici, la classe Sparrow adhère au LSP car les moineaux peuvent effectivement voler. Cependant, la classe Ostrich viole LSP car elle remplace la méthode voo() d'une manière qui modifie fondamentalement son comportement, brisant ainsi les attentes définies par la classe Ave.

Comment réparer ?

Il faudra appliquer le LSP en divisant chaque spécificité des classes Sparrow et Autruche en contrats (interfaces ou classes abstraites, ici j'utiliserai des interfaces) qu'elles devront signer pour moduler les comportements de chacun :

Fichier : bird.java

interface Bird {
    String getName();
    void makeSound();
}

interface FlyingBird extends Bird {
    void fly();
}

class Sparrow implements FlyingBird {
    private String name;

    public Sparrow(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public void makeSound() {
        System.out.println("Chirp chirp!");
    }

    @Override
    public void fly() {
        System.out.println(this.name + " is flying!");
    }
}

class Ostrich implements Bird {
    private String name;

    public Ostrich(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public void makeSound() {
        System.out.println("Boom boom!");
    }
}

public class Main {
    public static void main(String[] args) {
        Sparrow sparrow = new Sparrow("Little Sparrow");
        sparrow.makeSound(); // Chirp chirp!
        sparrow.fly(); // Little Sparrow is flying!

        Ostrich ostrich = new Ostrich("Ostrich");
        ostrich.makeSound(); // Boom boom!
        ostrich.fly(); // Error: Method 'fly' does not exist on 'Ostrich'
    }
}
Copier après la connexion

Fichier : oiseau.ts

interface Bird {
  name: string;
  makeSound(): void;
}

interface FlyingBird extends Bird {
  fly(): void;
}

class Sparrow implements FlyingBird {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  makeSound() {
    console.log("Chirp chirp!");
  }

  fly() {
    console.log(`${this.name} is flying!`);
  }
}

class Ostrich implements Bird {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  makeSound() {
    console.log("Boom boom!");
  }
}

const sparrow = new Sparrow("Little Sparrow");
sparrow.makeSound(); // Chirp chirp!
sparrow.fly(); // Little Sparrow is flying!

const ostrich = new Ostrich("Ostrich");
ostrich.makeSound(); // Boom boom!
ostrich.fly(); // Error: Method 'fly' does not exist on 'Ostrich'
Copier après la connexion

Analyse

Explication des corrections
Interface Bird : définit les comportements communs à tous les oiseaux, tels que makeSound(). Tous les oiseaux doivent implémenter cette interface.

Interface FlyingBird : hérite d'Ave et ajoute le comportement fly(), spécifique aux oiseaux capables de voler.

Classe Sparrow : implémente l'interface FlyingBird, puisque les moineaux peuvent voler. Cette classe définit le comportement d'émission du son et de vol.

Classe d'autruche : implémente uniquement l'interface Bird, car les autruches ne peuvent pas voler. Cette classe n'a pas la méthode fly() et ne viole donc pas LSP.

Conclusion

LSP est crucial pour garantir que le code est modulaire, réutilisable et facile à maintenir. Les violations du LSP peuvent conduire à un code fragile qui se brise lorsque de nouvelles sous-classes sont introduites ou lorsque des sous-classes existantes sont modifiées, car cela peut conduire à un comportement inattendu dans les parties du code qui dépendent de la superclasse.

La substitution de sous-type permet d'étendre un module sans modification, ce qui est essentiel pour la flexibilité fournie par le principe ouvert/fermé (OCP), rendue possible par le principe de substitution de Liskov. Les contrats (implémentés via des interfaces ou des classes abstraites) sont cruciaux pour une conception sécurisée, mais ils doivent être bien compris par les programmeurs, afin d'éviter les erreurs courantes dans les logiciels existants. Ils fournissent également de précieux conseils sur la manière de mettre en œuvre et d'utiliser le code, simplement en respectant le contrat en question.

Implications pratiques

  1. Lors de la conception de sous-classes, assurez-vous qu'elles peuvent être utilisées partout où leur superclasse est utilisée, sans introduire de bugs ni nécessiter de manipulation particulière.
  2. Évitez de créer des sous-classes qui violent le comportement attendu de la superclasse, car cela peut entraîner des problèmes de maintenance et des bugs inattendus.

Comprendre et appliquer le principe de substitution de Liskov aide les développeurs à créer des systèmes orientés objet plus prévisibles et plus stables.

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
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!