Modèles de Conception - Design Patterns

Modèles de Conception (Design Patterns)

L'un des premiers travail d'un concepteur Objet est de repérer les opportunités d'implémentations.

Généralités

Un patron de conception (design pattern en anglais) est un concept de génie logiciel destiné à résoudre les problèmes récurrents suivant le paradigme objet. C'est une solution de conception efficace et éprouvée de conception Orientée Objet.

Les patrons de conception décrivent des solutions standard pour répondre à des problèmes d'architecture et de conception des logiciels. À la différence d'un algorithme qui s'attache à décrire d'une manière formelle comment résoudre un problème particulier, les patrons de conception décrivent des procédés de conception généraux. On peut considérer un patron de conception comme une formalisation de bonnes pratiques, ce qui signifie qu'on privilégie les solutions éprouvées.

L'objectif d'un Pattern est multiple:
  • L'identification, la nomenclature: afin de reconnaître les Patterns dans une conception ou de discuter des Patterns applicables, il faut établir un langage commun et donc nommer tous les Patterns et les définir de manière univoque.
  • L'efficacité, l'élévation du niveau de langage: avoir un mot connu pour évoquer un principe de conception éventuellement complexe (qui met en oeuvre plusieurs classes et associations) permet de communiquer plus vite, d'éviter les ambiguïtés et de gagner en clarté. La contre-partie, évidemment, est que chaque interlocuteur doit avoir appris ce nouveau langage de Patterns.
  • L'enseignement: un novice en conception Orientée Objet apprend énormément en lisant la description et la motivation des Design Patterns et en essayant de les mettre en pratique sur ses projets. Par contre, comme certains de ces concepts sont assez abstraits, il ne faut pas s'effrayer de ne pas en percevoir toutes les implications à la première lecture: il faut avoir alterné lecture et mise en application plusieurs fois pour maîtriser tous les enjeux des Patterns.

On recense 3 grandes catégories de modèles.

Construction

Les modèles dits par construction.

Fabrique

Fabrique (Factory Method) : Elle permet d'instancier des objets dont le type est dérivé d'un type abstrait. La classe exacte de l'objet n'est donc pas connue par l'appelant.

Fabrique abstraite

Plusieurs fabriques peuvent être regroupées en une fabrique abstraite permettant d'instancier des objets dérivant de plusieurs types abstraits différents.

Monteur

Monteur (Builder) : utilisé pour la création d'une variété d'objets complexes à partir d'un objet source. L'objet source peut consister en une variété de parties contribuant individuellement à la création de chaque objet complet grâce à un ensemble d'appels à l'interface commune de la classe abstraite Monteur. Son but est de séparer la construction d'un objet complexe de la représentation afin que le même processus de construction puisse créer différentes représentations.

Prototype (Prototype)

yes

Singleton 

pattern

Comportemental

Les modèles dits par construction.

Chaîne de responsabilité


Commande


Interpréteur

Iterator

Parcourir une collection.

Médiateur

Organiser la réponse à une requête.  

Mémento


Observateur

Etat

Maintenir l'état d'un objet.

Stratégie

Sélection d’algorithme à la volée

Template Method


Structural

Les modèles dits de structure.

Adaptateur 

Adaptateur (Adapter) : permet de convertir l'interface d'une classe en une autre interface que le client attend. L’adaptateur fait fonctionner ensemble des classes qui n'auraient pas pu fonctionner sans lui, à cause d'une incompatibilité d'interfaces

Bridge

Pont (Bridge)

Composite

Objet composite (Composite)

Décorateur 

Facade

Poids-mouche




Dépasser les limitations de l'Objet


<note important>Les Design Patterns sont contre-nature.</note>

Les meilleures techniques de conception Objet sont aujourd'hui bien connues et répertoriées sous forme de catalogues de Design Patterns. Grâce à cet effort de documentation de la part des experts et à la bonne adoption de ces Patterns par les concepteurs et les développeurs, un certain nombre de réflexes ont pu se mettre en place:

* De plus en plus de projets sont organisés en couches de responsabilité bien identifiées.
* Chaque couche est généralement exposée par le biais d'une ou plusieurs Façade. Les Façades sont souvent des Singletons.
* Les couches d'accès aux données "simples" emploient très souvent un objet intermédiaire pour limiter le couplage entre les objets métier et la structure de la base de données: un DAO (Data Access Object), parfois associé à une Fabrique de DAO.
* Les couches plus fines d'accès aux données, souvent intégrées aux frameworks de mapping Objet/Relationnel peuvent utiliser une Fabrique de Poids Mouches (Flyweight), ou du moins une fabrique de Proxies (l'objectif étant d'implémenter un cache intelligent des objets persistants et de ne cloner un objet que lorsqu'un utilisateur lui apporte une modification et que l'on ne souhaite pas la répercuter sur l'activité des autres utilisateurs avant une validation et un enregistrement en base de données).
* Il est rare de voir des couches de présentation qui n'implémentent pas le pattern MVC (Modèle Vue Contrôleur).

Bref, les applications multi-couches modernes sont truffées de Design Patterns. D'ailleurs, les frameworks de développement tels que J2EE et .NET aussi: on y trouve les patterns Observer, Itérateur, Singleton et Fabrique à plusieurs reprises.

Ce n'est certainement pas moi qui vais militer contre les Design Patterns: je suis intimement convaincu de leur utilité, de la souplesse et parfois même des performances qu'ils amènent aux applications.



Mais analysons froidement les applications actuelles:

* Elles regorgent de Patterns, ce qui nécessite de travailler avec des développeurs-concepteurs toujours plus compétents. Ces derniers doivent connaître leur(s) langage(s) de programmation, les responsabilités de chaque couche de l'application, ainsi qu'une trentaine de Patterns en moyenne.
* L'utilisation systématique de Patterns est à double tranchant: le projet peut gagner en lisibilité pour les nouveaux entrants qui connaissent déjà tous les Patterns utilisés, mais peut s'avérer impénétrable pour ceux qui n'ont pas cette connaissance.
* L'application de Design Patterns fait très souvent apparaître de nouvelles classes. Si cette approche amène à une évolutivité supérieure et donc une maintenance évolutive plus aisée, elle rend plus coûteuses les phases de refactoring et de maintenance corrective.
* Enfin, les développeurs d'objets métier ou de services applicatifs se doivent d'appliquer les Patterns adéquats.

Revenons sur ce dernier point: il signifie que le modèle des objets métier ou de la couche de service doit être conforme aux Design Patterns. De manière un peu raccourcie, nous pourrions reformuler cela en: "il faut polluer le modèle métier de Patterns de conception". Il sera donc très difficile d'implémenter un modèle qui soit purement du niveau métier; généralement, la couche métier intègre des classes issues de l'analyse et de la conception (donc entre autres celles induites par l'application de Design Patterns).

Pour les puristes, cela pose deux problèmes. Tout d'abord, un problème de traçabilité car les concepts métier se voient implémentés en plusieurs classes: si nous prenons l'exemple du Pattern Etat, et si un objet peut se trouver dans n états, il sera implémenté en au moins n+2 classes (la classe issue de l'analyse, un état abstrait et une classe concrète pour chaque état différent). Que ce soit dans les diagrammes UML ou dans le code du projet, il est difficile de séparer très clairement le métier des artifices techniques apportés par la conception (même si, dans les diagrammes, l'utilisation de couleurs ou de stéréotypes aide à la lisibilité).

Le deuxième problème est celui de l'affectation des responsabilités, à la fois aux composants et aux personnes qui les développent. Quelle classe porte les informations ou la compétence métier?
Quelle classe offre un découplage par rapport aux couches connexes ou par rapport à un framework quelconque (de traces, de distribution, de présentation, de persistance...)? Il devient subtil de répondre à ces questions. Or dans l'idéal, il faudrait séparer la responsabilité de l'analyste de celle du concepteur. Allons plus loin, il faudrait que l'analyste puisse travailler sur des classes que le concepteur ne
modifierait pas ou peu par la suite. Ainsi, les problèmes de "round-trip engineering" pourraient enfin se réduire voire disparaître puisque le couplage des itérations d'analyse et de conception s'affaiblirait.
Pour résumer, nous sommes tous convaincus de l'intérêt des Design Patterns. Mais ils représentent une compétence et une responsabilité techniques qui doivent être décorrélées de l'analyse (et de la programmation) d'objets métier. Le travail des concepteurs et des équipes responsables des frameworks doit pouvoir être découplé du travail d'analyse fonctionnelle! Dans la section suivante, nous allons passer en revue les diverses solutions ou tendances actuelles qui vont dans ce sens.

Commentaires

Posts les plus consultés de ce blog

Sécurité des Applications

Principes de la Programmation Orientée Objet

Principe de Responsabilité Unique