Patron de conception
En informatique, et plus particulièrement en développement logiciel, un patron de conception (souvent appelé design pattern) est un arrangement caractéristique de modules, reconnu comme bonne pratique en réponse à un problème de conception d'un logiciel. Il décrit une solution standard, utilisable dans la conception de différents logiciels[1].
Un patron de conception est issu de l'expérience des concepteurs de logiciels[2]. Il décrit un arrangement récurrent de rôles et d'actions joués par des modules d'un logiciel, et le nom du patron sert de vocabulaire commun entre le concepteur et le programmeur[3]. D'une manière analogue à un motif de conception en architecture, le patron de conception décrit les grandes lignes d'une solution, qui peuvent ensuite être modifiées et adaptées en fonction des besoins[4].
Les patrons de conception décrivent des procédés de conception généraux et permettent en conséquence de capitaliser l'expérience appliquée à la conception de logiciel. Ils ont une influence sur l'architecture logicielle d'un système informatique.
Types de patrons
Les patrons de conception ne sont ni des patrons d'architecture ni des idiotismes de programmation.
- Un patron de conception est la meilleure solution connue à un problème de conception récurrent.
- Un patron d'architecture est la meilleure solution connue à un problème d'architecture récurrent. Il apporte des solutions sur la manière de concevoir l'organisation à grande échelle (architecture) d'un logiciel en faisant abstraction des détails. Il concerne la structure générale d'un logiciel, sa subdivision en unités plus petites, comporte des guides de bonnes pratiques et des règles générales qui ne peuvent pas être traduites directement en code source[5].
- Le patron de conception suggère un arrangement, une manière d'organiser des modules ou des classes. Il décrit une organisation de classes fréquemment utilisée pour résoudre un problème récurrent. Le patron de conception parle d'instances, de rôles et de collaboration[5].
- L'idiotisme de programmation est une construction spécifique à un langage de programmation, qui est une manière usuelle de mettre en œuvre une solution à un problème dans ce langage de programmation. Par exemple pour effectuer cent fois une opération, un programmeur en langage C utilise les instructions
for (i = 0; i < 100; i++)
pour sa ligne de code. L'utilisation d'un idiotisme par le programmeur lui évite d'avoir à remettre en question la structure détaillée du programme et améliore la qualité du produit[5].
Description
Les patrons servent à documenter des bonnes pratiques basées sur l'expérience. Ils proposent des solutions à des problèmes qui peuvent être difficilement résolus par un seul composant : la description de la plupart des patrons implique plusieurs rôles qui peuvent être joués par plusieurs composants d'un logiciel. Par exemple, le patron Observer implique deux rôles qui sont le sujet et l'observateur[6].
Les patrons apportent un vocabulaire commun entre l'architecte informatique et le programmeur. Si le programmeur connaît le patron de conception observer, alors l'architecte informatique n'aura pas besoin de lui donner de longues explications et le dialogue se limitera à « ici, j'ai utilisé un Observer »[6].
En programmation informatique, les patrons de conception peuvent être utilisés avant, pendant, ou après le travail de programmation : utilisé avant, le programmeur utilisera le patron comme guide lors de l'écriture du code source ; utilisé après, il servira comme exemple pour relier différents modules de code source déjà écrits, ce qui implique d'écrire le code source nécessaire à leur liaison, et le code qui les fera correspondre au patron de conception ; s'il est utilisé pendant le travail de programmation, le programmeur constatera que le code qui vient d'être écrit a des points communs avec un patron existant et effectuera les modifications nécessaires pour que le code corresponde au patron[7]. La bonne pratique consiste toutefois à n'utiliser un patron qu'une fois qu'il est clair que sa flexibilité est nécessaire[8].
Histoire
Formalisés dans le livre du « Gang of Four » (GoF, Erich Gamma, Richard Helm, Ralph Johnson (en) et John Vlissides (en)) intitulé Design Patterns – Elements of Reusable Object-Oriented Software[9] en 1994. Les patrons de conception tirent leur origine des travaux de l'architecte Christopher Alexander dans les années 70, dont son livre A Pattern Language définit un ensemble de patrons d'architecture.
Citations
- « Chaque patron décrit un problème qui se manifeste constamment dans notre environnement, et donc décrit le cœur de la solution à ce problème, d’une façon telle que l’on puisse réutiliser cette solution des millions de fois, sans jamais le faire deux fois de la même manière » — Christopher Alexander, 1977.
- « Les patrons offrent la possibilité de capitaliser un savoir précieux né du savoir-faire d’experts » — Buschmann, 1996.
Formalisme
La description d'un patron de conception suit un formalisme fixe :
- Nom ;
- Description du problème à résoudre ;
- Description de la solution : les éléments de la solution, avec leurs relations. La solution est appelée patron de conception ;
- Conséquences : résultats issus de la solution.
Ce formalisme aide surtout à mieux comprendre l'utilisation et la logique interne de chaque patron, mais ne correspond pas à l'usage habituel du terme. Le mot structure serait peut-être plus adapté.
Un aspect de construction plus important est l'orthogonalité : chaque patron doit correspondre à une approche différente, qui ne répète pas les idées ou stratégies présentes dans d'autres patrons. Cette qualité permet au concepteur d'analyser un problème et d'en résoudre chaque aspect d'une façon organisée, ainsi que de combiner les patrons pour construire une solution. Certains auteurs voient un manque d'orthogonalité dans les patrons GoF, tandis que d'autres en proposent encore davantage (Vlissides, Grand).
Patrons de conception du GoF
Les patrons de conception ont été formellement reconnus en 1994 à la suite de la parution du livre Design Patterns: Elements of Reusable Software, co-écrit par quatre auteurs : Gamma, Helm, Johnson et Vlissides (Gang of Four - GoF ; en français « la bande des quatre »). Ce livre, devenu un best-seller, décrit vingt-trois « patrons GoF » et comment s'en servir[10].
Il existe trois familles de patrons de conception selon leur utilisation :
- créateurs : ils définissent comment faire l'instanciation et la configuration des classes et des objets ;
- structuraux : ils définissent comment organiser les classes d'un programme dans une structure plus large (séparant l'interface de l'implémentation) ;
- comportementaux : ils définissent comment organiser les objets pour que ceux-ci collaborent (distribution des responsabilités) et expliquent le fonctionnement des algorithmes impliqués.
Les vingt-trois patrons GoF :
- Fabrique et Fabrique abstraite
- Ce patron fournit une interface pour créer des familles d'objets sans spécifier la classe concrète[11]. Le patron fabrique, ou méthode fabrique (en anglais factory ou factory method) est un patron récurrent. Une fabrique simple retourne une instance d'une classe parmi plusieurs possibles, en fonction des paramètres qui ont été fournis. Toutes les classes ont un lien de parenté, et des méthodes communes, et chacune est optimisée en fonction d'une certaine donnée[10]. Le patron fabrique abstraite (en anglais abstract factory) va un peu plus loin que la fabrique simple. Une fabrique abstraite est utilisée pour obtenir un jeu d'objets connexes. Par exemple pour implémenter une charte graphique : il existe une fabrique qui retourne des objets (boutons, menus) dans le style de Windows, une qui retourne des objets dans le style de Motif, et une dans le style de Macintosh. Une fabrique abstraite est obtenue en utilisant une fabrique simple[10].
- Adaptateur
- Ce patron convertit l'interface d'une classe en une autre interface exploitée par une application. Permet d'interconnecter des classes qui sans cela seraient incompatibles[11]. Il est utilisé dans le cas où un programme se sert d'une bibliothèque de classe qui ne correspond plus à l'utilisation qui en est faite, à la suite d'une mise à jour de la bibliothèque dont l'interface a changé. Un objet adaptateur (en anglais adapter) expose alors l'ancienne interface en utilisant les fonctionnalités de la nouvelle[12].
- Pont
- Ce patron permet de découpler une abstraction de son implémentation, de telle manière qu'ils peuvent évoluer indépendamment[11]. Il consiste à diviser une implémentation en deux parties : une classe d'abstraction qui définit le problème à résoudre, et une seconde classe qui fournit une implémentation. Il peut exister plusieurs implémentations pour le même problème et la classe d'abstraction comporte une référence à l'implémentation choisie, qui peut être changée selon les besoins[13]. Le patron pont (en anglais bridge) est fréquemment utilisé pour réaliser des récepteurs d'événements[14].
- Monteur
- Ce patron sépare le processus de construction d'un objet du résultat obtenu. Permet d'utiliser le même processus pour obtenir différents résultats[11]. C'est une alternative au pattern fabrique. Au lieu d'une méthode pour créer un objet, à laquelle est passée un ensemble de paramètres, la classe fabrique comporte une méthode pour créer un objet — le monteur (en anglais builder). Cet objet comporte des propriétés qui peuvent être modifiées et une méthode pour créer l'objet final en tenant compte de toutes les propriétés. Ce pattern est particulièrement utile quand il y a de nombreux paramètres de création, presque tous optionnels[15].
- Chaîne de responsabilité
- Le patron chaîne de responsabilité (en anglais chain of responsibility) vise à découpler l’émission d'une requête de la réception et le traitement de cette dernière en permettant à plusieurs objets de la traiter successivement[11]. Dans ce patron chaque objet comporte un lien vers l'objet suivant, qui est du même type. Plusieurs objets sont ainsi attachés et forment une chaîne. Lorsqu'une demande est faite au premier objet de la chaîne, celui-ci tente de la traiter, et s'il ne peut pas il fait appel à l'objet suivant, et ainsi de suite[16].
- Commande
- Ce patron emboîte une demande dans un objet, permettant de paramétrer, mettre en file d'attente, journaliser et annuler des demandes[11]. Dans ce patron un objet commande (en anglais command) correspond à une opération à effectuer. L'interface de cet objet comporte une méthode
execute
. Pour chaque opération, l'application va créer un objet différent qui implémente cette interface — qui comporte une méthodeexecute
. L'opération est lancée lorsque la méthodeexecute
est utilisée. Ce patron est notamment utilisé pour les barres d'outils[17]. - Composite
- Le patron composite (même nom en anglais) permet de composer une hiérarchie d'objets, et de manipuler de la même manière un élément unique, une branche, ou l'ensemble de l'arbre[11]. Il permet en particulier de créer des objets complexes en reliant différents objets selon une structure en arbre. Ce patron impose que les différents objets aient une même interface, ce qui rend uniformes les manipulations de la structure. Par exemple dans un traitement de texte, les mots sont placés dans des paragraphes disposés dans des colonnes dans des pages ; pour manipuler l'ensemble, une classe composite implémente une interface. Cette interface est héritée par les objets qui représentent les textes, les paragraphes, les colonnes et les pages[18].
- DĂ©corateur
- Le patron décorateur (en anglais decorator) permet d'attacher dynamiquement des responsabilités à un objet. Une alternative à l'héritage[11]. Ce patron est inspiré des poupées russes. Un objet peut être caché à l'intérieur d'un autre objet décorateur qui lui rajoutera des fonctionnalités, l'ensemble peut être décoré avec un autre objet qui lui ajoute des fonctionnalités et ainsi de suite. Cette technique nécessite que l'objet décoré et ses décorateurs implémentent la même interface, qui est typiquement définie par une classe abstraite[19].
- Façade
- Le patron façade (en anglais facade) fournit une interface unifiée sur un ensemble d'interfaces d'un système[11]. Il est utilisé pour réaliser des interfaces de programmation. Si un sous-système comporte plusieurs composants qui doivent être utilisés dans un ordre précis, une classe façade sera mise à disposition, et permettra de contrôler l'ordre des opérations et de cacher les détails techniques des sous-systèmes[20].
- Flyweight
- Dans le patron flyweight (en français poids-mouche), un type d'objet est utilisé pour représenter une gamme de petits objets tous différents[11]. Ce patron permet de créer un ensemble d'objets et de les réutiliser. Il peut être utilisé par exemple pour représenter un jeu de caractères : un objet factory va retourner un objet correspondant au caractère recherché. La même instance peut être retournée à chaque fois que le caractère est utilisé dans un texte[20].
- Interpreter
- Le patron comporte deux composants centraux : le contexte et l'expression[20] ainsi que des objets qui sont des représentations d'éléments de grammaire d'un langage de programmation[11]. Le patron est utilisé pour transformer une expression écrite dans un certain langage de programmation — un texte source — en quelque chose de manipulable par programmation[20] : Le code source est écrit conformément à une ou plusieurs règles de grammaire, et un objet est créé pour chaque utilisation d'une règle de grammaire. L'objet interpreter est responsable de transformer le texte source en objets[21].
- Iterator
- Ce patron permet d'accéder séquentiellement aux éléments d'un ensemble sans connaitre les détails techniques du fonctionnement de l'ensemble[11]. C'est un des patrons les plus simples et les plus fréquents. Selon la spécification originale, il consiste en une interface qui fournit les méthodes
Next
etCurrent
. L'interface en Java comporte généralement une méthodenextElement
et une méthodehasMoreElements
[10]. - Mediator
- Dans ce patron il y a un objet qui définit comment plusieurs objets communiquent entre eux en évitant à chacun de faire référence à ses interlocuteurs[11]. Ce patron est utilisé quand il y a un nombre non négligeable de composants et de relations entre les composants. Par exemple dans un réseau de 5 composants il peut y avoir jusqu'à vingt relations (chaque composant vers quatre autres). Un composant médiateur est placé au milieu du réseau et le nombre de relations est diminué : chaque composant est relié uniquement au médiateur[22]. Le mediator joue un rôle similaire à un sujet dans le patron observer et sert d'intermédiaire pour assurer les communications entre les objets[23].
- Memento
- Ce patron vise à externaliser l'état interne d'un objet sans perte d'encapsulation. Permet de remettre l'objet dans l'état où il était auparavant[11]. Ce patron permet de stocker l'état interne d'un objet sans que cet état ne soit rendu public par une interface. Il est composé de trois classes : l'origine — d'où l'état provient, le memento —, l'état de l'objet d'origine, et le gardien qui est l'objet qui manipulera le memento. L'origine comporte une méthode pour manipuler les memento. Le gardien est responsable de stocker les memento et de les renvoyer à leur origine. Ce patron ne définit pas d'interface précise pour les différents objets, qui sont cependant toujours au nombre de trois[24].
- Observer
- Ce patron établit une relation un à plusieurs entre des objets, où lorsqu'un objet change, plusieurs autres objets sont avisés du changement[11]. Dans ce patron, un objet le sujet tient une liste des objets dépendants des observateurs qui seront avertis des modifications apportées au sujet. Quand une modification est apportée, le sujet émet un message aux différents observateurs. Le message peut contenir une description détaillée du changement[23]. Dans ce patron, un objet observer comporte une méthode pour inscrire des observateurs. Chaque observateur comporte une méthode
Notify
. Lorsqu'un message est émis, l'objet appelle la méthodeNotify
de chaque observateur inscrit[25]. - Prototype
- Ce patron permet de définir le genre d'objet à créer en dupliquant une instance qui sert d'exemple — le prototype[11]. L'objectif de ce patron est d'économiser le temps nécessaire pour instancier des objets. Selon ce patron, une application comporte une instance d'un objet, qui sert de prototype. Cet objet comporte une méthode
clone
pour créer des duplicata. Des langages de programmation comme PHP ont une méthodeclone
incorporée dans tous les objets[26]. - Proxy
- Ce patron est un substitut d'un objet, qui permet de contrôler l'utilisation de ce dernier[11]. Un proxy est un objet destiné à protéger un autre objet. Le proxy a la même interface que l'objet à protéger. Un proxy peut être créé par exemple pour permettre d’accéder à distance à un objet (via un middleware). Le proxy peut également être créé dans le but de retarder la création de l'objet protégé — qui sera créé immédiatement avant d'être utilisé. Dans sa forme la plus simple, un proxy ne protège rien du tout et transmet tous les appels de méthode à l'objet cible[14].
- Singleton
- Ce patron vise à assurer qu'il n'y a toujours qu'une seule instance d'une classe en fournissant une interface pour la manipuler[11]. C'est un des patrons les plus simples. L'objet qui ne doit exister qu'en une seule instance comporte une méthode pour obtenir cette unique instance et un mécanisme pour empêcher la création d'autres instances[16].
- State
- Ce patron permet à un objet de modifier son comportement lorsque son état interne change[11]. Ce patron est souvent utilisé pour implémenter une machine à états. Un exemple d'appareil à états est le lecteur audio — dont les états sont lecture, enregistrement, pause et arrêt. Selon ce patron il existe une classe machine à états, et une classe pour chaque état. Lorsqu'un événement provoque le changement d'état, la classe machine à états se relie à un autre état et modifie ainsi son comportement[27].
- Strategy
- Dans ce patron, une famille d'algorithmes est encapsulée de manière qu'ils soient interchangeables. Les algorithmes peuvent changer indépendamment de l'application qui s'en sert[11]. Il comporte trois rôles : le contexte, la stratégie et les implémentations. La stratégie est l'interface commune aux différentes implémentations — typiquement une classe abstraite. Le contexte est l'objet qui va associer un algorithme avec un processus[20].
- Template method
- Ce patron définit la structure générale d'un algorithme en déléguant certains passages. Permettant à des sous-classes de modifier l'algorithme en conservant sa structure générale[11]. C'est un des patrons les plus simples et les plus couramment utilisés en programmation orientée objet. Il est utilisé lorsqu'il y a plusieurs implémentations possibles d'un calcul. Une classe d'exemple (anglais template) comporte des méthodes d'exemple, qui, utilisées ensemble, implémentent un algorithme par défaut. Certaines méthodes peuvent être vides ou abstraites. Les sous-classes de la classe template peuvent remplacer certaines méthodes et ainsi créer un algorithme dérivé[21].
- Visitor
- Ce patron représente une opération à effectuer sur un ensemble d'objets. Permet de modifier l'opération sans changer l'objet concerné ni la structure[11]. Selon ce patron, les objets à modifier sont passés en paramètre à une classe tierce qui effectuera des modifications. Une classe abstraite Visitor définit l'interface de la classe tierce. Ce patron est utilisé notamment pour manipuler un jeu d'objets, où les objets peuvent avoir différentes interfaces, qui ne peuvent pas être modifiés[20].
Patrons GRASP
Les patrons GRASP (general responsibility assignment software patterns (ou principles)) sont des patrons créés par Craig Larman qui décrivent des règles pour affecter les responsabilités aux classes d'un programme orienté objet pendant la conception, en liaison avec la méthode de conception BCE (pour boundary control entity — en français MVC « modèle vue contrôleur »)[28] :
- expert ;
- créateur ;
- faible couplage ;
- forte cohésion ;
- contrĂ´leur ;
- polymorphisme ;
- indirection ;
- fabrication pure ;
- protection des variations.
Autres patrons de conception
- Object Pool
- Ce patron permet d'économiser les temps d'instanciation et de suppression lorsque de nombreux objets ont une courte durée d'utilisation. Il consiste à administrer une collection d'objets qui peuvent être recyclés. Une méthode du Pool délivre un objet soit par une nouvelle instanciation, soit par recyclage d'un objet périmé. Lorsque les objets arrivent à la fin de leur cycle de vie, ils sont remis à la disposition du Pool pour un futur recyclage. Dans la phase d'instanciation, le Pool peut instancier plus d'un objet à la fois si l'algorithme d'instanciation a une complexité meilleure que O(n). Le patron Object Pool est particulièrement utile lorsque le nombre total de cycles de vie est très grand devant le nombre d'instances à un moment précis et que les opérations d'instanciation et/ou suppression sont coûteuses en temps d'exécution par rapport à leur recyclage.
- Modèle-vue-contrôleur
- Combinaison des patrons observateur, stratégie et composite, ce qui forme ainsi un patron d'architecture.
- Inversion de contrĂ´le
- Injection de dépendances
Notes et références
- (en) Rajib Mall, Fundamentals of Software Engineering, PHI Learning Pvt. Ltd. (ISBN 9788120338197), p. 266.
- Laurent Debrauwer, Design patterns pour Java : Les 23 modèles de conception : descriptions et solutions illustrées en UML 2 et Java, ENI, 2009 (ISBN 978-2-74605057-0).
- (en) Frank Buschmann, Kevlin Henney et Douglas C. Schmidt, Pattern-oriented software architecture: On patterns and pattern languages, John Wiley and Sons, 2007 (ISBN 9780471486480), p. 13.
- (en) Linda Rising, The Patterns Handbook: Techniques, Strategies, and Applications, Cambridge University Press, 1998 (ISBN 9780521648189), p. 311.
- (en) Rajib Mall, Fundamentals of Software Engineering, op. cit., p. 267
- (en) Buschmann, Henney et Schmidt, Pattern-oriented software architecture: On patterns and pattern languages, op. cit.
- (en) Stephen Hendrick Kaisler, Software Paradigms, John Wiley and Sons, p. 39, 2005 (ISBN 9780471483472).
- (en) Bill Venners, « Erich Gamma on Flexibility and Reuse, A Conversation with Erich Gamma, Part II ». « Bill Venners: So what do the XP guys do first, if they don't use patterns? They just write the code? Erich Gamma: They write a test. Bill Venners: Yes, they code up the test. And then when they implement it, they just implement the code to make the test work. Then when they look back, they refactor, and maybe implement a pattern? Erich Gamma: Or when there's a new requirement. »
- Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (trad. Jean-Marie Lasvergères), Design Patterns - Catalogue de modèles de conceptions réutilisables, France, Vuibert, , 490 p. [détail des éditions] (ISBN 2-71178-644-7)
- (en) James William Cooper, Java Design Patterns: A Tutorial, Addison-Wesley Professional - 2000 (ISBN 9780201485394).
- (en) Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Pearson Education - 1994 (ISBN 9780321700698).
- (en) Steve Holzner, Design Patterns For Dummies, John Wiley & Sons, , 308 p. (ISBN 978-0-470-04696-8, lire en ligne)
- (en) Stephen Stelting - Olav Maassen, Applied Java Patterns, Prentice Hall Professional - 2002 (ISBN 9780130935380).
- (en) Dustin Diaz - Ross Harmes, Pro JavaScript Design Patterns, Apress - 2007 (ISBN 9781430204961).
- (en) Joshua Bloch, Effective Java, Addison-Wesley Professional - 2008 (ISBN 9780132778046).
- (en) Carlo Chung, Pro Objective-C Design Patterns for iOS, Apress - 2011 (ISBN 9781430233305).
- (en) Andrei Alexandrescu, Modern C++ Design: Generic Programming and Design Patterns Applied, Addison-Wesley Professional - 2001 (ISBN 9780201704310).
- (en) Mark Grand, Patterns in Java: A Catalog of Reusable Design Patterns Illustrated with UML, Volume 1, John Wiley & Sons - 2003 (ISBN 9780471449331).
- (en) Joey Lott, Danny Patterson, Advanced ActionScript with Design Patterns, Adobe Press (ISBN 9780132701372).
- (en) Christopher G. Lasater, Design Patterns, Jones & Bartlett Publishers - 2010 (ISBN 9781449612887).
- (en) Partha Kuchana, Software Architecture Design Patterns in Java, CRC Press - 2004 (ISBN 9780203496213).
- (en) John Hunt, Scala Design Patterns: Patterns for Practical Reuse and Design, Springer Science & Business Media - 2013 (ISBN 9783319021928).
- (en) Addy Osmani, Learning JavaScript Design Patterns, O'Reilly Media, Inc. - 2012 (ISBN 9781449334871).
- (en) Joey Lott - Danny Patterson, Advanced ActionScript with Design Patterns, Adobe Press (ISBN 9780132701372).
- (en) Chaur Wu - Tom Fischer - Pete Stromquist - John Slater, Professional Design Patterns in VB .NET: Building Adaptable Applications, Apress - 2003 (ISBN 9781430207832).
- (en) William Sanders, Learning PHP Design Patterns, O'Reilly Media, Inc. - 2013 (ISBN 9781449344917).
- (en) William Sanders - Chandima Cumaranatunge, ActionScript 3.0 Design Patterns: Object Oriented Programming Techniques, O'Reilly Media, Inc. - 2007 (ISBN 9780596554842).
- Craig Larman, UML 2 et les Design Patterns, 3e Ă©d. (ISBN 2-7440-7090-4).
Voir aussi
Bibliographie
- Christopher Alexander, S. Ishikawa, M. Silverstein, M. Jacobson, I. Fiksdahl-King and S. Angel, (1977), A Pattern Language : Towns, Buildings, Construction, (ISBN 0-19-501919-9)
- Pattern Languages of Program Design - James O. Coplien, Douglas C. Schmidt. (1995), (ISBN 0-201-60734-4)
Articles connexes
Liens externes
- Liste des patrons de conception avec exemples, problèmes, solutions et solutions alternatives.
- Le catalogue des patrons de conception