Site icon Blog ARC Optimizer

Principe solide | AU NOUVEAU BLOG

Principe solide |  AU NOUVEAU BLOG


Introduction

Les principes SOLID ont été développés par Robert C. Martin dans un essai de 2000, « Design Principles and Design Patterns », bien que l’acronyme ait été inventé plus tard par Michael Feathers. Dans son essai, Martin a reconnu que les logiciels performants changeront et se développeront. À mesure que cela évolue, cela devient de plus en plus complexe. Sans bons principes de conception, Martin prévient que les logiciels deviennent rigides, fragiles, immobiles et vicieux. Les principes SOLID ont été développés pour lutter contre ces modèles de conception problématiques.

But

L’objectif général des principes SOLID est de réduire les dépendances afin que les ingénieurs modifient une zone du code logiciel sans affecter les autres. De plus, ils visent à rendre les conceptions plus faciles à comprendre, à maintenir et à étendre. En fin de compte, ces principes de conception permettent aux ingénieurs logiciels d’éviter plus facilement les problèmes et de créer des logiciels adaptatifs, efficaces et agiles.

Acronyme SOLID – c’est un acronyme qui représente cinq principes de conception clés :

  1. Principe de responsabilité unique (SRP)
  2. Principe Ouvert Fermé (OCP)
  3. Principe de substitution de Liskov (LSP)
  4. Principe de ségrégation d’interface (ISP)
  5. Principe d’inversion de dépendance (DIP)

Les ingénieurs logiciels utilisent couramment les cinq et offrent des avantages importants aux développeurs. Avantages des principes SOLID : –

  1. Réduire la complexité du code.
  2. Augmentez la lisibilité, l’extensibilité et la maintenance.
  3. Augmentez l’évolutivité, la flexibilité du code et la lisibilité.
  4. Obtenez une meilleure testabilité.
  5. Réduisez les couplages serrés.
  6. Réduisez les erreurs et implémentez la réutilisabilité.
  7. Augmenter le développement parallèle.

Discutons des cinq principes avec quelques exemples. Ici, j’utiliserai le langage de programmation Java pour les exemples.

Principe de responsabilité unique (SRP)

Le principe de responsabilité unique stipule : « Chaque module ou classe logiciel ne devrait avoir qu’une seule raison de changer. « En d’autres termes, on peut dire que chaque module ou classe ne devrait avoir qu’une seule responsabilité à accomplir. Nous devons concevoir le logiciel de manière à ce que tout dans une classe ou un module soit lié à une seule responsabilité. Cela ne veut pas dire que votre classe ne doit avoir qu’une seule méthode ou propriété ; vous pouvez avoir plusieurs membres (méthodes ou propriétés) à condition qu’ils soient tous liés à une seule responsabilité ou fonctionnalité. Grâce au principe de responsabilité unique, les classes deviennent plus petites et plus propres, ce qui facilite leur entretien.

Dans cet exemple, la classe BankService a une seule responsabilité, qui consiste à déposer et retirer de l’argent. La classe PrinterService a une seule responsabilité : imprimer le Passbook. Les deux classes se concentrent sur une tâche unique et bien définie et n’ont qu’une seule raison de changer. Cela rend le code plus facile à comprendre, à maintenir et à tester.

Principe ouvert-fermé (OCP)

Le principe ouvert/fermé est l’un des principes SOLID de la conception logicielle, qui suggère que les entités logicielles telles que les classes, les modules et les fonctions doivent être ouvertes pour extension mais fermées pour modification. Ce principe stipule que vous devriez pouvoir ajouter de nouvelles fonctionnalités à un système sans avoir à modifier le code existant. En d’autres termes, vous devriez pouvoir étendre le comportement d’un système sans modifier sa base de code existante. Ceci est important car modifier le code existant peut entraîner des conséquences imprévues et introduire des bugs, tandis qu’étendre le comportement d’un système peut améliorer ses fonctionnalités sans affecter négativement son code existant. Considérons un exemple Java pour illustrer le principe ouvert/fermé. Supposons que nous disposions d’un système de notification de base pour envoyer à l’utilisateur l’OTP et le rapport de transaction.

Désormais, nous avons la possibilité d’envoyer l’OTP et le rapport de transaction via différents supports à l’utilisateur, sans modifier le code existant. Pour ce faire, nous pouvons créer une nouvelle classe qui étend la classe NotificationService et implémenter les méthodes suivantes :

Cette nouvelle classe EmailNotificationService et SMSNotificationService ajoute la possibilité de partager l’OTP. Il rend compte à l’utilisateur via un support différent, mais il le fait en étendant la classe NotificationService plutôt qu’en la modifiant. Cela signifie que la classe NotificationService reste inchangée et que nous pouvons continuer à l’utiliser de la même manière qu’auparavant.

Comme vous pouvez le constater, nous pouvons utiliser les classes Email et SMSNotificationService de manière interchangeable car elles ont toutes deux des méthodes avec la même signature.

En résumé, le principe ouvert/fermé est un principe important de conception logicielle qui suggère que les entités logicielles doivent être ouvertes à l’extension mais fermées à la modification. Dans l’exemple ci-dessus, nous avons démontré comment étendre le comportement d’un système de notification en ajoutant une nouvelle classe EmailNotificationService qui étend la classe NotificationService existante, sans modifier sa base de code existante.

Principe de substitution de Liskov

Le principe de substitution de Liskov (LSP) est un principe de programmation orientée objet qui stipule que les objets d’une superclasse doivent être remplaçables par des objets d’une sous-classe sans affecter l’exactitude du programme. Cela signifie qu’une sous-classe doit être un sous-type de sa superclasse et que les objets de la sous-classe doivent pouvoir être utilisés partout où des objets de la superclasse sont attendus sans introduire de nouveaux bogues ni provoquer la rupture d’une fonctionnalité existante. Le LSP est important pour créer un code maintenable et flexible. Si une sous-classe n’est pas un sous-type approprié de sa superclasse, l’utilisation d’un objet de la sous-classe à la place d’un objet de la superclasse peut provoquer un comportement inattendu, conduisant à des bogues difficiles à localiser et à corriger. Pour garantir qu’une sous-classe est un sous-type approprié de sa superclasse, elle doit remplir les exigences suivantes :

  1. La sous-classe doit avoir toutes les propriétés et méthodes de la superclasse.
  2. La sous-classe ne doit pas avoir de nouvelles propriétés ou méthodes qui ne figurent pas dans la superclasse.
  3. La sous-classe ne doit pas réduire la visibilité des propriétés ou méthodes de la superclasse.
  4. La sous-classe ne doit pas modifier le comportement des propriétés ou des méthodes de la superclasse d’une manière qui briserait le code existant qui utilise la superclasse.

Pour illustrer le LSP, considérons l’exemple Java. Supposons que nous ayons une classe SocialMedia contenant différentes fonctionnalités telles que chatWithFriend, submitPost, sendPhotosAndVideos, etc. Lorsque des classes comme Instagram, Facebook et WhatsApp vont étendre SocialMedia, nous devons également étendre ces fonctionnalités, qui ne font pas partie de cette plate-forme. .

Pour résoudre ce problème et adhérer au principe de substitution de Liskov, nous devons modifier la conception de la classe SocialMedia et la diviser en classes plus abstraites comme PostMediaManager, SocialVideoCallManager, etc. Nous allons maintenant créer différentes classes de plate-forme de médias sociaux comme Facebook, Instagram, etc. Facebook étendra les classes abstraites qui lui sont applicables uniquement.

En utilisant une classe SocialMedia distincte, nous pouvons garantir qu’un objet SocialMedia peut être remplacé par un objet Facebook, Instagram ou Whatsapp sans violer l’exactitude du programme. En suivant le LSP, nous pouvons créer une base de code flexible et maintenable, dans laquelle des objets de différentes classes peuvent être utilisés de manière interchangeable sans provoquer de comportement inattendu. Cela facilite l’extension et la modification de notre code selon les besoins sans introduire de nouveaux bugs.

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

Il stipule qu’un client ne doit pas être obligé de dépendre d’interfaces qu’il n’utilise pas. En d’autres termes, il est préférable d’avoir plusieurs petites interfaces adaptées à des besoins spécifiques plutôt qu’une seule grande interface qui tente de tout couvrir. Pour illustrer le principe de ségrégation des interfaces, considérons un exemple Java. Supposons que nous ayons une interface UPIPayments, avec des méthodes pour payer, obtenir des cartes à gratter et obtenir du cashback :

Pour adhérer au principe de ségrégation des interfaces, nous pouvons diviser l’interface UPIPayments en deux interfaces plus petites, une pour les méthodes qui s’appliquent à chaque plateforme et une autre pour une plateforme spécifique, à savoir CashBackManager, et l’implémenter en conséquence.

Dans cette nouvelle implémentation, la classe PhonePe n’a besoin que d’implémenter l’interface UPIPayments, et la classe GooglePay peut implémenter les interfaces UPIPayments et CashBackManager. Cela adhère au principe de ségrégation des interfaces, car chaque classe ne dépend que des interfaces qu’elle utilise. Le principe de ségrégation des interfaces est un principe important de la conception logicielle qui encourage l’utilisation d’interfaces plus petites et plus ciblées plutôt que de grandes interfaces monolithiques. Dans l’exemple Java ci-dessus, nous avons montré comment refactoriser l’interface UPIPayments pour adhérer au principe de ségrégation d’interface et éviter les couplages inutiles et les comportements inattendus.

Principe d’inversion de dépendance (DIP)

Il stipule que les modules de haut niveau ne doivent pas dépendre des modules de bas niveau. Au lieu de cela, les deux devraient dépendre d’abstractions. Cela favorise un couplage lâche et une flexibilité, facilitant ainsi les modifications sans affecter les autres parties du système. Pour illustrer le principe d’inversion de dépendance, considérons un exemple Java. Supposons que nous ayons une classe BankCard qui doit utiliser une classe DebitCard/CreditCard pour effectuer la transaction dans le centre commercial. Dans cet exemple, la classe BankCard représente un module de haut niveau et la classe DebitCard/CreditCard représente un module de bas niveau.

Dans cette implémentation, la classe BankCard instancie directement un objet DebitCard/CreditCard dans son constructeur. Cela viole le principe d’inversion de dépendance car la classe BankCard dépend d’un module de bas niveau, ce qui la rend inflexible et étroitement couplée.
Pour adhérer au principe d’inversion de dépendance, nous pouvons utiliser une abstraction, telle qu’une interface ou une classe abstraite, pour découpler la classe BankCard de la classe DebitCard/CreditCard. Nous pouvons définir une interface DebitCard/CreditCard pour effectuer la transaction puis injecter une instance de cette interface dans la classe BankCard :

Dans cette nouvelle implémentation, la classe BankCard ne dépend plus de la classe DebitCard/CreditCard mais plutôt de l’interface DebitCard/CreditCard. Nous pouvons désormais créer plusieurs implémentations de l’interface DebitCard/CreditCard, qui peuvent être utilisées pour effectuer la transaction différemment. Cela rend la classe BankCard plus flexible et plus facile à modifier, car elle n’est plus étroitement couplée à la DebitCard/CreditCard.

Conclusion

Dans l’exemple Java ci-dessus, nous avons montré comment utiliser une abstraction, telle qu’une interface, pour découpler un module de haut niveau d’un module de bas niveau, rendant ainsi le code plus flexible et plus facile à modifier.

Pour rester à jour avec le monde en constante évolution des API, des microservices et de la transformation numérique. Suivez-nous sur les réseaux sociaux pour plus de mises à jour.






Source link
Quitter la version mobile