Maison > Java > javaDidacticiel > le corps du texte

Principes SOLIDES

Linda Hamilton
Libérer: 2024-10-21 06:12:02
original
893 Les gens l'ont consulté

SOLID Principles

SOLID est un ensemble de principes fondamentaux conçus pour améliorer la gérabilité et l'évolutivité du code dans la programmation orientée objet (POO). Il se compose de cinq principes clés :

  1. SPrincipe de responsabilité unique — SRP
  2. O stylo-Principe fermé — OCP
  3. LPrincipe de substitution d'Iskov — LSP
  4. IPrincipe de ségrégation d'interface — ISP
  5. D Principe d'inversion de dépendance — DIP

Ces principes ont été introduits par Robert C. Martin (également connu sous le nom d'Oncle Bob) au début des années 2000 et ont depuis été largement adoptés dans la communauté du développement logiciel. En suivant les principes SOLID, les développeurs peuvent créer un code plus facile à comprendre, à modifier et à étendre, conduisant à des systèmes logiciels plus robustes et plus maintenables.

Principe de responsabilité unique (SRP)

Le principe de responsabilité unique est le premier et le plus fondamental des principes POO et SOLID. Comme son nom l'indique, ce principe signifie « Une classe ne devrait avoir qu'une seule responsabilité spécifique à assumer ».

Supposons que nous ayons une classe appelée Invoice , qui contient 2 méthodes generateInvoice() et saveToFiles() .

public class Invoice {
  private Long InvoiceNo;

  public void generateInvoice() {
    // code to generate Invoice.
  }

  public void saveToFiles() {
    // code to save invoice as a file.
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Ce n'est pas une bonne pratique car la classe Invoice a deux responsabilités. Une meilleure approche serait de séparer ces fonctionnalités en classes dédiées.

public class Invoice {
  private Long InvoiceNo;

  public void generateInvoice() {
    // code to generate Invoice.
  }
}

public class FileManager {
  public void saveToFiles(Invoice invoice) {
    // code to save invoice as a file.
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Ici, nous pouvons voir que nous avons 2 classes pour le cas d'utilisation :

  • Génération de la facture
  • Enregistrez-le dans des fichiers

Avantages de suivre le SRP

  • Organisation améliorée du code : en séparant les préoccupations en différentes classes, la base de code devient plus organisée et plus facile à naviguer.
  • Meilleure maintenabilité : Lorsqu'une classe a une seule responsabilité, il est plus facile de comprendre son objectif et d'apporter des modifications sans effets secondaires involontaires.
  • Réutilisabilité accrue : Les classes avec une seule responsabilité sont plus susceptibles d'être réutilisables dans différentes parties de l'application ou même dans d'autres projets.
  • Tests plus faciles : les classes avec une seule responsabilité sont généralement plus petites et plus ciblées, ce qui les rend plus faciles à tester de manière isolée.

Principe ouvert-fermé (OCP)

Le principe ouvert-fermé est un autre principe fondamental de SOLID. Ce principe a été introduit par Bertrand Meyer en 1997. L'idée derrière ce principe est « Les artefacts logiciels (classes, modules et fonctions) doivent s'ouvrir pour les extensions, mais fermés pour les modifications. »

Par exemple ;

Disons que nous avons une classe appelée Shape , nous pouvons utiliser cette classe pour calculer l'aire de la forme.

public class Invoice {
  private Long InvoiceNo;

  public void generateInvoice() {
    // code to generate Invoice.
  }

  public void saveToFiles() {
    // code to save invoice as a file.
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans le code ci-dessus, l'ajout d'une nouvelle forme nécessite de modifier la classe Shape existante, ce qui n'est pas considéré comme une bonne pratique.

Vous trouverez ci-dessous un exemple de code qui montre comment appliquer le principe ouvert-fermé à ce scénario.

public class Invoice {
  private Long InvoiceNo;

  public void generateInvoice() {
    // code to generate Invoice.
  }
}

public class FileManager {
  public void saveToFiles(Invoice invoice) {
    // code to save invoice as a file.
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Avec l'application d'OCP, nous pouvons ajouter autant de formes que nous le souhaitons sans modifier l'implémentation actuelle.

REMARQUE : L'utilisation d'interfaces n'est pas le seul moyen d'atteindre l'OCP.

Avantages de suivre l’OCP

  • Risque réduit de bugs : En ne modifiant pas le code existant, le risque d'introduire de nouveaux bugs ou de casser des fonctionnalités existantes est minimisé.
  • Maintenabilité améliorée : Le code qui suit l'OCP est plus facile à maintenir et à étendre, car de nouvelles fonctionnalités peuvent être ajoutées sans altérer la base de code existante.
  • Flexibilité améliorée : L'utilisation d'abstractions et de polymorphisme permet des conceptions plus flexibles et adaptables, ce qui facilite l'adaptation aux exigences changeantes.

Principe de substitution de Liskov (LSP)

Le principe de substitution de Liskov est un autre principe important en POO. Il a été introduit par Barbara Liskov en 1987 lors d'une conférence sur l'abstraction de données.

Le principe stipule : « Les objets d'une superclasse doivent être remplaçables par des objets de ses sous-classes sans altérer l'exactitude du programme ».

Par exemple, si Circle et Rectangle sont des sous-types de Shape, alors nous devrions pouvoir remplacer l'objet Shape par un objet Circle ou Rectangle sans aucun problème.

public class Shape {
    private String shapeType;
    private double radius;
    private double length;
    private double width;

    public Shape(String shapeType, double radius, double length, double width) {
        this.shapeType = shapeType;
        this.radius = radius;
        this.length = length;
        this.width = width;
    }

    public double area() {
        if (shapeType.equals("circle")) {
            return Math.PI * (radius * radius);
        } else if (shapeType.equals("rectangle")) {
            return length * width;
        } else {
            throw new IllegalArgumentException("Unknown shape type");
        }
    }
}

// Usage
public class Main {
    public static void main(String[] args) {
        Shape circle = new Shape("circle", 5, 0, 0);
        Shape rectangle = new Shape("rectangle", 0, 4, 6);

        System.out.println(circle.area());
        System.out.println(rectangle.area());
    }
}
Copier après la connexion
Copier après la connexion

Comme démontré dans cet exemple, adhérer au principe de substitution de Liskov signifie que nous devrions pouvoir remplacer de manière transparente une instance de superclasse par une instance de sous-classe.

Avantages de suivre LSP

  • Réutilisabilité améliorée du code : En garantissant que les sous-types peuvent être remplacés par leurs types de base, le code qui utilise le type de base peut également fonctionner avec n'importe lequel de ses sous-types, favorisant ainsi la réutilisation du code.
  • Maintenabilité améliorée : Le code qui suit LSP est plus facile à maintenir car il réduit le risque d'introduction de bugs lors de la modification ou de l'extension de la base de code.
  • Meilleure testabilité : LSP facilite l'écriture de tests unitaires pour les classes et leurs sous-types, car les tests peuvent être écrits sur le type de base et devraient fonctionner pour tous les sous-types.

Principe de ségrégation d'interface (ISP)

Le principe de ségrégation d'interface est l'un des cinq principes SOLID introduits par Robert C. Martin. Il précise : « Les clients ne devraient pas être obligés de dépendre d’interfaces qu’ils n’utilisent pas ».

En d'autres termes, il est préférable d'utiliser de nombreuses interfaces spécifiques à des tâches plutôt que d'utiliser une seule interface à usage général.

L'exemple ci-dessous montre l'utilisation d'une interface à usage général.

public class Invoice {
  private Long InvoiceNo;

  public void generateInvoice() {
    // code to generate Invoice.
  }

  public void saveToFiles() {
    // code to save invoice as a file.
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

L'utilisation d'une interface généraliste comme MultifonctionPrinter nous oblige à implémenter des méthodes inutiles, ce qui est considéré comme une mauvaise pratique. Explorons comment nous pouvons appliquer le principe de ségrégation d'interface à ce scénario.

Interfaces

public class Invoice {
  private Long InvoiceNo;

  public void generateInvoice() {
    // code to generate Invoice.
  }
}

public class FileManager {
  public void saveToFiles(Invoice invoice) {
    // code to save invoice as a file.
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Implémentations

public class Shape {
    private String shapeType;
    private double radius;
    private double length;
    private double width;

    public Shape(String shapeType, double radius, double length, double width) {
        this.shapeType = shapeType;
        this.radius = radius;
        this.length = length;
        this.width = width;
    }

    public double area() {
        if (shapeType.equals("circle")) {
            return Math.PI * (radius * radius);
        } else if (shapeType.equals("rectangle")) {
            return length * width;
        } else {
            throw new IllegalArgumentException("Unknown shape type");
        }
    }
}

// Usage
public class Main {
    public static void main(String[] args) {
        Shape circle = new Shape("circle", 5, 0, 0);
        Shape rectangle = new Shape("rectangle", 0, 4, 6);

        System.out.println(circle.area());
        System.out.println(rectangle.area());
    }
}
Copier après la connexion
Copier après la connexion

En appliquant le FAI, nous l'avons divisé en interfaces plus petites et spécifiques à des rôles — comme une imprimante, un scanner et un fax. Cela permet à chaque classe (par exemple BasicPrinter, AdvancedPrinter ou FaxMachine) d'implémenter uniquement les fonctionnalités pertinentes, favorisant la modularité et réduisant les dépendances inutiles.

Avantages de suivre un FAI

  • Code modulaire et réutilisable : En décomposant les grandes interfaces en plus petites et plus spécifiques, le code devient plus modulaire et réutilisable. Les classes ou modules peuvent implémenter uniquement les interfaces dont ils ont besoin, réduisant ainsi les dépendances inutiles et facilitant la réutilisation du code dans différentes parties du système.
  • Complexité du code réduite : Lorsque des classes ou des modules dépendent uniquement des interfaces dont ils ont besoin, le code devient moins complexe et plus facile à comprendre. En effet, les développeurs n'ont pas à gérer des méthodes ou des dépendances inutiles. Ceux-ci ne sont pas pertinents pour leur cas d'utilisation spécifique.
  • Maintenabilité améliorée : Avec des interfaces plus petites et plus ciblées, il devient plus facile de maintenir le code. Les modifications apportées à une interface sont moins susceptibles d'affecter d'autres parties du système, ce qui réduit le risque d'introduction de bugs ou de rupture de fonctionnalités existantes.
  • Meilleure testabilité : des interfaces plus petites et plus ciblées facilitent l'écriture de tests unitaires pour des composants individuels. En effet, les tests peuvent se concentrer sur des comportements spécifiques sans être affectés par des méthodes ou des dépendances non pertinentes.
  • Flexibilité accrue : En adhérant au FAI, le système devient plus flexible et plus facile à étendre ou à modifier. De nouvelles fonctionnalités ou exigences peuvent être ajoutées en créant de nouvelles interfaces ou en modifiant celles existantes sans affecter l'ensemble du système.

Principe d'inversion de dépendance (DIP)

Le principe d'inversion de dépendance est le principe final de SOLID. Qui a également été introduit par Robert C. Martin. Cela favorise un code faiblement couplé.

DIP indique quelques points :

  • Les modules de haut niveau ne doivent pas dépendre des modules de bas niveau.
  • Les deux devraient dépendre de l'abstraction.
  • L'abstraction ne doit pas dépendre des détails.
  • Les détails devraient dépendre de l'abstraction.

En termes simples, au lieu d'une classe dépendant directement d'autres classes spécifiques (implémentations concrètes), elle devrait dépendre d'interfaces ou classes abstraites. Cela rend le code plus flexible et plus facile à maintenir, car vous pouvez échanger les implémentations sans modifier la classe dépendante.

Code étroitement couplé (sans DIP)

public class Invoice {
  private Long InvoiceNo;

  public void generateInvoice() {
    // code to generate Invoice.
  }

  public void saveToFiles() {
    // code to save invoice as a file.
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Comme le montre l'exemple ci-dessus, la classe Computer dépend directement de la classe Keyboard.

Code faiblement couplé (avec DIP)

public class Invoice {
  private Long InvoiceNo;

  public void generateInvoice() {
    // code to generate Invoice.
  }
}

public class FileManager {
  public void saveToFiles(Invoice invoice) {
    // code to save invoice as a file.
  }
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Maintenant, l'ordinateur dépend de l'interface InputDevice, et non d'un clavier spécifique. Cela facilite le passage à un autre périphérique d'entrée, comme un clavier sans fil, sans modifier la classe Computer.

Avantages de suivre le DIP

  • Couplage lâche : En dépendant d'abstractions plutôt que d'implémentations concrètes, le code devient moins étroitement couplé, ce qui facilite la modification d'une partie du système sans affecter les autres.
  • Maintenabilité améliorée : Les modifications apportées aux modules de bas niveau n'impactent pas les modules de haut niveau, ce qui rend le système plus facile à maintenir et à étendre.
  • Testabilité améliorée : les modules de haut niveau peuvent être testés à l'aide d'implémentations simulées des modules de bas niveau, ce qui rend les tests plus rapides et plus fiables.
  • Réutilisabilité accrue : Les modules de haut niveau peuvent être réutilisés dans différents contextes sans avoir besoin de modifier les modules de bas niveau dont ils dépendent.

Conclusion

En conclusion, les principes SOLID : responsabilité unique, ouvert-fermé, substitution de Liskov, ségrégation d'interface et inversion de dépendance fournissent des lignes directrices essentielles pour écrire du code propre, maintenable et évolutif dans la programmation orientée objet.

En adhérant à ces principes, les développeurs peuvent créer des systèmes plus faciles à comprendre, à modifier et à étendre, conduisant finalement à des logiciels de meilleure qualité et à des processus de développement plus efficaces.

Résumé

Merci d’avoir lu cet article ! J'espère que vous avez maintenant une solide compréhension des principes SOLID et de la manière dont vous pouvez les appliquer pour améliorer vos projets.

Suivez-moi sur :
  • LinkedIn — @nsadisha
  • GitHub — @nsadisha
  • Moyen — @nsadisha
  • Dev.to — @nsadisha

—Sadisha Nimsara

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
Derniers articles par auteur
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!