gwift-book/source/part-1-workspace/solid.adoc

6.0 KiB
Raw Blame History

SOLID

  1. S : SRP (Single Responsibility

  2. O : Open closed

  3. L : LSP (Liskov Substitution)

  4. I : Interface Segregation

  5. D : Dependency Inversion

Single Responsibility Principle

Le principe de responsabilité unique définit que chaque concept ou domaine dactivité ne soccupe que dune et dune seule chose. En prenant lexemple dune méthode qui communique avec une base de données, ce ne sera pas à cette méthode à gérer linscription dune exception à un emplacement quelconque. Cette action doit être prise en compte par une autre classe (ou un autre concept), qui soccupera elle de définir lemplacement où lévènement sera enregistré (base de données, Graylog, fichier, …​).

Cette manière dorganiser le code ajoute une couche dabstraction (ie. "I dont care") sur les concepts, et centralise tout ce qui touche à type dévènement à un et un seul endroit. Ceci permet également de centraliser la configuration pour ce type dévènements, et augmenter la testabilité du code.

Open Closed

Un des principes essentiels en programmation orientée objets est lhéritage de classes et la surcharge de méthodes: plutôt que de partir sur une série de comparaisons pour définir le comportement dune instance, il est parfois préférable de définir une nouvelle sous-classe, qui surcharge une méthode bien précise. Pour lexemple, on pourrait ainsi définir trois classes:

  • Une classe Customer, pour laquelle la méthode GetDiscount ne renvoit rien;

  • Une classe SilverCustomer, pour laquelle la méthode revoit une réduction de 10%;

  • Une classe GoldCustomer, pour laquelle la même méthode renvoit une réduction de 20%.

Si on rencontre un nouveau type de client, il suffit alors de créer une nouvelle sous-classe. Cela évite davoir à gérer un ensemble conséquent de conditions dans la méthode initiale, en fonction dune autre variable (ici, le type de client).

En anglais, dans le texte : "Putting in simple words the “Customer” class is now closed for any new modification but its open for extensions when new customer types are added to the project.". En résumé: on ferme la classe Customer à toute modification, mais on ouvre la possibilité de créer de nouvelles extensions en ajoutant de nouveaux types [héritant de Customer].

Liskov Substitution

Le principe de substitution fait quune classe B qui hérite dune classe A doit se comporter de la même manière que cette dernière. Il nest pas question que la classe B nimplémente pas certaines méthodes, alors que celles-ci sont disponibles pour A.

[…​] if S is a subtype of T, then objects of type T in a computer program may be replaced with objects of type S (i.e., objects of type S may be substituted for objects of type T), without altering any of the desirable properties of that program (correctness, task performed, etc.). (Source: Wikipédia).

Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S, where S is a subtype of T. (Source: Wikipédia aussi)

Ce principe sapplique à tout type de polymorphisme, et même aux langages de type duck typing: "when I see a bird that quacks like a duck, walks like a duck, has feathers and webbed feet and associates with ducks—Im certainly going to assume that he is a duck" (Source: Wikipedia (as usual)). Pour le cas émis ci-dessus, ce nest donc pas parce quune classe a besoin dune méthode définie dans une autre classe quelle doit forcément en hériter. Cela bousillerait le principe de substitution (et par la même occasion le duck test).

Interface Segregation

Ce principe stipule quun client ne peut en aucun cas dépendre dune méthode dont il na pas besoin. Plus simplement, plutôt que de dépendre dune seule et même (grosse) interface présentant un ensemble conséquent de méthodes, il est proposé dexploser cette interface en plusieurs (plus petites) interfaces. Ceci permet aux différents clients de nutiliser quun sous-ensemble précis dinterfaces, répondant chacune à un besoin particulier.

Lexemple par défaut est davoir une interface permettant daccéder à des éléments. Modifier cette interface pour permettre lécriture impliquerait que toutes les applications ayant déjà accès à la première, obtiendraient (par défaut) un accès en écriture, ce qui nest pas souhaité/souhaitable.

Pour contrer ceci, on aurait alors une première interface permettant la lecture, tandis quune deuxième (héritant de la première) permettrait lécriture. On aurait alors le schéma suivant :

  • A : lecture

  • B (héritant de A) : lecture (par A) et écriture.

Dependency inversion

Dans une architecture conventionnelle, les composants de haut-niveau dépendant directement des composants de bas-niveau. Une manière très simple dimplémenter ceci est dinstancier un nouveau composant. Linversion de dépendances stipule que cest le composant de haut-niveau qui possède la définition de linterface dont il a besoin, et le composant de bas-niveau qui limplémente.

Le composant de haut-niveau peut donc définir quil sattend à avoir un Publisher pour publier du contenu vers un emplacement particulier. Plusieurs implémentation de cette interface peuvent alors être mise en place:

  • Une publication par SSH

  • Une publication par FTP

  • Une publication

  • …​

Linjection de dépendances est un patron de programmation qui suit le principe dinversion de dépendances.