Je souhaite revenir aujourd’hui sur un sujet qui, à mes yeux, est très important mais malheureusement assez méconnu des développeurs : les design patterns. Lors des quelques entretiens que j’ai pu faire passer, je me suis rendu compte que cette notion est soit mal maitrisée (quelques mots-clés/buzzword cités ça et là mais sans réelle explication derrière) soit carrément inconnue ! Je trouve ça dommage car c’est quelque chose de très utile dans son travail quotidien et nous allons voir pourquoi dans cet article.

Qu’est-ce que c’est ?

Schéma formant une solution reconnue comme fiable et robuste (aka. bonne pratique) à un problème connu ou récurrent

A partir de cette définition, on peut donc dire que les design patterns (patrons de conception en français) naissent via l’expérience. En effet, être confronté plusieurs fois à un même problème permet d’améliorer et d’affiner à chaque fois la solution qu’on y apporte. Au bout d’un moment, en fédérant les travaux d’autres personnes ayant été confrontées au même problème, on va finir par aboutir à une solution qui s’avère être la mieux adaptée pour ce problème précis. Il suffit ensuite d’en retirer la moelle pour obtenir un modèle réutilisable permettant de résoudre le problème de manière efficace et performante.

Un design pattern est donc une capitalisation du travail. On peut y voir 3 points positifs :

  1. Évite de réinventer la roue !

  2. Gain de temps

  3. Permet de s’assurer que l’on applique une “bonne” solution (fiable, robuste et éprouvée)

Attention, ce n’est pas une notion propre à l’informatique. On retrouve ce concept dans des domaines comme la construction, les mathématiques ou même l’art.

Design Pattern = Nom + Problème + Solution + Conséquence

Historiquement, les design patterns proviennent des travaux de Christopher Alexander (architecte) dans les années 70 et ont été formalisés dans le livre “Design Patterns – Elements of Reusable Object-Oriented Software” du Gang Of Four en 1995 (ou GoF : groupe de 4 informaticiens, Erich Gamma, Richard Helm, Ralph Johnson et John Vlissides, auteurs de nombreux ouvrages en programmation orientée objet). Les patrons de conception ont été divisés par le GoF en 3 catégories que nous allons parcourir ensemble. Je vais essayer de vous les décrire le plus précisément possible et tenter de faire le lien avec mon langage, le C#.

Les principes “SOLID”

La programmation orientée objet c’est bien sûr le polymorphisme, l’héritage et l’encapsulation. Mais en plus de ces notions de base relativement théoriques, et juste avant de parcourir les différents patterns, je souhaite faire un tour sur 5 principes importants de la POO regroupés sous l’acronyme SOLID (Robert C. Martin). Tout développeur, en particulier en entreprise, se doit de les connaitre. Ils permettent de garantir une évolution simple, une maintenance efficace et une bonne robustesse des applications que l’on développe.

SRP : Single Responsability Principle

~ Principe de responsabilité unique

Une classe doit avoir une et une seule raison de changer. Si une classe a plus d’une responsabilité, alors ces responsabilités deviennent couplées et des modifications apportées à l’une peuvent porter atteinte à l’autre.

OCP : Open/Close Principle

~ Principe d’ouvert/fermé

Les entités logicielles doivent être ouvertes pour l’extension mais fermées à la modification.

Autrement dit, une classe doit pouvoir être étendue mais sans modification de son code. On peut répondre à ce principe avec différents moyens, comme l’abstraction, la généricité ou certains design patterns (Factory par exemple). Cela permet de limiter fortement les risques de régression. Elle reste bien sûr ouverte à la modification en cas de défaut (bug).

LSP : Liskov Substitution Principle

~ Principe de substitution de Liskov

Tout type de base doit pouvoir être remplacé par l’un de ses sous-types.

L’exemple le plus connu est celui du rectangle et du carré et je vous invite à aller lire l’article de Wikipédia à ce sujet, il est très bien fait. Généralement, la bonne solution pour respecter ce principe est de manipuler des interfaces ou d’utiliser l’héritage.

ISP : Interface Segregation Principle

~ Principe de ségrégation des interfaces

Un client ne doit jamais être forcé de dépendre d’une interface qu’il n’utilise pas.

L’idée est donc de découper au mieux nos interfaces par besoin. Cela facilite le décomposition et la compréhension. Attention tout de même à ne pas abuser de ce principe, car on peut très vite se retrouver avec une démultiplication des interfaces qui deviendra contre-productive.

La classe List du framework .NET est une excellente illustration de ce principe : IList, ICollection, IReadOnlyList, IEnumerable… chacune ayant un rôle précis et bien défini.

DIP : Dependency Inversion Principle

~ Principe de l’inversion des dépendances

Il ne faut pas dépendre (directement) de l’implémentation bas niveau que vous allez utiliser.

Les modules haut niveau regroupent les fonctionnalités métier et ceux de bas niveau les briques techniques (communication, log, persistance…). L’idée est que les points de contact entre les modules soient matérialisés par des abstractions pour réduire le couplage et faciliter le remplacement d’un module de bas niveau (changement de base de données par exemple).

Pour comprendre de manière un peu plus fun ces 5 principes, je vous invite à aller lire cet article qui les illustre par des situations de la vie courante. Croyez-moi, c’est vraiment excellent !

Quel est le programme ?

Pour éviter un article trop long et indigeste, je vais découper la suite en plusieurs articles, chacun dédiés à une catégorie de pattern :

Pour conclure, je vous invite tout de même à rester pragmatique par rapport à ce que vous allez lire. En effet, ces principes, règles et patterns ne sont que des outils permettant de faciliter la rédaction du code et la création d’applications robustes et évolutives et ils ne sont donc pas toujours à prendre au pied de la lettre. En fonction de la criticité du module que vous écrivez, il ne sera pas forcément indispensable de mettre en œuvre une usine à gaz ! Vous pouvez aussi très bien faire une première version “simple” que vous ferez évoluer au fur et à mesure des besoins (et à ce moment il sera peut-être nécessaire d’appliquer ces principes).