Concept: Mécanismes de conception et d'implémentation
Un mécanisme de conception ajoute des détails concrets au mécanisme d'analyse conceptuelle, mais ne requiert pas de technologie particulière.
Relations
Description principale

Présentation des mécanismes de conception et d'implémentation

Un mécanisme de conception est le perfectionnement du mécanisme d'analyse correspondant (voir aussi Concept : Mécanismes d'analyse). Un mécanisme de conception ajoute des détails concrets au mécanisme d'analyse conceptuelle, tout en ne nécessitant pas de technologie particulière - par exemple l'implémentation par un fournisseur particulier d'un système de gestion de base de données orientée objet. Comme les mécanismes d'analyse, un mécanisme de conception peut instancier un ou plusieurs patterns, en l'occurrence des patterns architecturaux ou des patterns de conception.

De la même façon, un mécanisme d'implémentation est le perfectionnement du mécanisme de conception correspondant, utilisant, par exemple, un langage de programmation spécifique ainsi qu'une autre technologie d'implémentation (comme le produit middleware d'un fournisseur spécifique.) Un mécanisme d'implémentation peut instancier un ou plusieurs schémas de mise en oeuvre ou patterns d'implémentation.

Exemple: Caractéristiques des mécanismes de conception

Observons les mécanismes d'analyse de la persistance :

  • Il peut être nécessaire de stocker de nombreux (2000) petits objets (200 octets chacun) pendant quelques secondes, sans besoin de survie.
  • Il peut être nécessaire de stocker plusieurs très gros objets sur disque en permanence pendant plusieurs mois, sans les mettre à jour, mais avec des moyens d'extraction sophistiqués.

Ces objets nécessiteront plusieurs supports de persistance ; on peut identifier les caractéristiques suivantes en ce qui concerne les mécanismes de conception pour la prise en charge de la persistance :

  • Stockage en mémoire ; caractéristiques : jusqu'à 1 Mo (taille x volume) ; accès très rapide en lecture, en écriture et en mise à jour.
  • Carte Flash ; caractéristiques : jusqu'à 8 Mo ; accès lent en mise à jour et en écriture ; moyen en lecture.
  • Fichier binaire ; caractéristiques : entre 100 Ko et 200 Mo ; mise à jour lente ; accès lent en lecture et en écriture.
  • Système de gestion de base de données (SGBD) ; caractéristiques : à partir de 100 Ko (il n'y a pratiquement pas de limite supérieure) ; accès encore plus lent en lecture, en écriture et en mise à jour.

Notez que ces vitesses ne sont jugées "lentes" que par rapport au stockage en mémoire. Visiblement, l'utilisation du stockage en mémoire cache peut améliorer les temps d'accès apparents dans certains environnements.

Diagramme détaillé dans le contenu.



Perfectionnement du mappage entre les mécanismes de conception et d'implémentation

Initialement, le mappage entre mécanismes de conception et d'implémentation ne sera probablement pas optimal mais il permettra au projet d'avancer, identifiera les risques pas encore décelés et entraînera des enquêtes et des évaluations supplémentaires. A mesure que le projet se poursuit et que le niveau de connaissance augmente, le mappage doit être perfectionné.

Il faut procéder de manière itérative pour perfectionner le mappage entre les mécanismes de conception et d'implémentation en éliminant les chemins redondants et en travaillant de manière "descendante" et "ascendante".

Travail descendant. Lorsque vous descendez, de nouvelles réalisations de cas d'utilisation perfectionnées vont dégager de nouvelles exigences dans les mécanismes de conception requis via les mécanismes d'analyse requis. Ces nouvelles exigences peuvent dégager certaines caractéristiques supplémentaires d'un mécanisme de conception, obligeant à séparer les mécanismes. Il y a également un compromis entre la complexité du système et ses performances :

  • Une trop grande variété de mécanismes de conception rend le système trop complexe.
  • Une trop faible diversité de ces mécanismes peut créer, pour certains mécanismes d'implémentation, des problèmes de performances qui repoussent les limites des plages raisonnables de leurs valeurs caractéristiques.

Travail ascendant. Lorsque vous remontez et examinez les mécanismes d'implémentation disponibles, vous pouvez trouver des produits répondant à plusieurs mécanismes de conception à la fois mais nécessitent d'adapter ou de séparer vos mécanismes de conception. Vous voulez minimiser le nombre de mécanismes d'implémentation que vous utilisez, mais une absence de diversité peut également poser des questions de performances.

Si vous décidez d'utiliser un SGBD pour stocker des objets de classe A, vous pourriez être tenté d'y recourir pour stocker tous les objets du système. Cela peut s'avérer particulièrement inefficace, ou encombrant. Tous les objets qui nécessitent de la persistance ne doivent pas forcément être stockés dans le SGBD. Certains objets peuvent être persistants mais peuvent être régulièrement appelés par l'application, et seulement rarement par d'autres applications. La meilleure approche peut consister en une stratégie hybride dans laquelle l'objet est lu à partir du SGBD vers la mémoire et périodiquement synchronisé.

Exemple

Un vol peut être stocké en mémoire pour un accès rapide, et dans un SGBD pour une persistance à long terme ; cela déclenche toutefois le besoin d'un mécanisme qui synchronise les deux.

Il n'est pas rare que plusieurs mécanismes de conception soient associés à une classe client comme compromis entre différentes caractéristiques.

Etant donné que les mécanismes d'implémentation prennent souvent la forme de groupes de composants standard (systèmes d'exploitation et middleware), il convient de réaliser une certaine optimisation que l'on basera sur le coût, le défaut d'adaptation d'impédance ou l'uniformité du style. Par ailleurs, les mécanismes sont souvent interdépendants, rendant difficile la séparation claire des services en mécanismes de conception.

Exemples

  • Le mécanisme de notification peut être basé sur le mécanisme de communication inter-processus.

  • Le mécanisme de rapport d'erreurs peut être basé sur le mécanisme de persistance.

Le perfectionnement se poursuit tout au long de la phase d'élaboration, et se présente toujours comme un compromis entre :

  • Une "correspondance" exacte du mécanisme de conception avec les exigences du client, en termes de caractéristiques attendues.
  • Le coût et la complexité que suppose le fait d'avoir trop de mécanismes d'implémentation différents à acquérir et à intégrer.

L'objectif général est toujours d'avoir un seul ensemble clair de mécanismes afin de donner à un système de grande taille une intégrité conceptuelle, de la simplicité et de l'élégance.

Exemple : Mappage des mécanismes de conception aux mécanismes d'implémentation

Les mécanismes de conception de persistance peuvent être mappés aux mécanismes d'implémentation de la manière suivante :

Diagramme détaillé dans le contenu.

Un mappage possible entre mécanismes d'analyse et mécanismes de conception. Les flèches en pointillés signifient "est spécialisé par", sous-entendu que les mécanismes de conception tiennent leurs caractéristiques des mécanismes d'analyse mais que celles-ci seront spécialisées et perfectionnées.

Une fois que vous avez terminé l'optimisation des mécanismes, les mappages suivants sont possibles :

Diagramme détaillé dans le contenu.

Les décisions de conception pour une classe client en termes de mappage entre mécanismes ; la classe de vol nécessite deux types de persistance : un stockage en mémoire implémenté par un sous-programme de bibliothèque prête à l'emploi, et un autre dans une base de données implémentée à l'aide d'un produit StockageObjet standard.

On doit pouvoir naviguer sur l'application dans les deux directions, de manière à ce qu'il soit facile de déterminer les classes client lors des changements de mécanismes d'implémentation.

Description des mécanismes de conception

Les mécanismes de conception, ainsi que les détails relatifs à leur utilisation, sont documentés dans le  Produit : Instructions relatives au projet. La relation (ou le mappage) des mécanismes d'analyse aux mécanismes de conception et d'implémentation, avec le raisonnement associé à ces choix, est documentée dans le Produit: Document d'architecture logicielle.

Comme pour les mécanismes d'analyse, les mécanismes de conception peuvent être modélisés à l'aide d'une collaboration qui peut instancier un ou plusieurs patterns d'architecture ou de conception.

Exemple : Un mécanisme de persistance

Cet exemple s'appuie sur une instance d'un pattern pour la persistance SGBDR, tiré de JDBC (Java Data Base Connectivity). Bien que nous présentions ici la conception, JDBC fournit du code pour certaines de ses classes ; il n'y a donc qu'un pas entre ce qui est présenté ici et un mécanisme d'implémentation.

La figure Vue statique : JDBC présente les classes (les rôles discriminants) de la collaboration.

Diagramme détaillé dans le contenu.

Vue statique : JDBC

Les classes en jaune sont celles qui ont été fournies, les autres (myDBClass, etc.) ont été ajoutées par le concepteur pour créer le mécanisme.

Dans JDBC, un client travaillera avec une classe de base de données (DBClass) pour lire et écrire les données persistantes. DBClass est chargée d'accéder à la base de données JDBC en utilisant la classe DriverManager. Dès qu'une connexion à la base de données est ouverte, DBClass peut créer des instructions SQL qui seront envoyées au SGBDR sous-jacent et exécutées au moyen de la classe Statement. La classe Statement représente l'élément qui "parle" à la base de données. Le résultat de la requête SQL est renvoyé dans un objet ResultSet. 

La classe DBClass est chargée de rendre persistante une autre instance de classe. Elle comprend le mappage OO-à-SGBDR et elle a le comportement idoine pour servir d'interface avec le SGBDR. La classe DBClass décompose l'objet, l'écrit dans le SGBDR et lit ses données  depuis le SGBDR, puis elle le construit. Chaque classe persistante aura une DBClass correspondante. 

PersistentClassList sert à renvoyer un ensemble d'objets persistants comme résultat d'une requête de base de données (par exemple, DBClass.read()).

Nous présentons maintenant une série de vues dynamiques, afin de montrer comment le mécanisme fonctionne réellement.

Diagramme détaillé dans le contenu.

JDBC : Initialiser

L'initialisation doit avoir lieu avant qu'il ne soit possible d'accéder à toute classe persistante.

Pour initialiser la connexion à la base de données, la classe DBClass doit charger le pilote approprié en appelant l'opération DriverManager getConnection() avec une URL, un utilisateur et un mot de passe.

L'opération getConnection() tente d'établir une connexion à l'URL de la base de données en question. DriverManager tente de sélectionner un pilote approprié dans l'ensemble de pilotes JDBC répertoriés.

Paramètres :

url : Une URL de base de données du type jdbc:sous-protocole:sous-nom. Cette URL sert à localiser le serveur de base de données et n'est, dans cet exemple, pas reliée au Web.

utilisateur : utilisateur de la base de données au nom duquel la connexion est établie

mot de passe : mot de passe de l'utilisateur

Renvoie :

une connexion à l'URL.

Diagramme détaillé dans le contenu.

JDBC : Créer

Pour créer une nouvelle classe, le client de persistance adresse sa demande à DBClass. Celle-ci crée une nouvelle instance de PersistentClass avec des valeurs par défaut. Puis elle crée une nouvelle instruction au moyen de l'opération createStatement() de la classe de connexion. L'instruction est exécutée et les données sont insérées dans la base de données.

Diagramme détaillé dans le contenu.

JDBC : Lire

Pour lire une classe persistante, le client de persistance adresse sa demande à la classe DBClass. Celle-ci crée alors une nouvelle instruction au moyen de l'opération createStatement() de la classe Connection. L'instruction est exécutée et les données sont renvoyées dans un objet ResultSet. DBClass crée alors une nouvelle instance de la classe PersistentClass et la remplit avec les données récupérées. Les données sont renvoyées dans un objet de type Collection, qui est une instance de la classe PersistentClassList.

Remarque : La chaîne transmise à executeQuery() n'est pas nécessairement exactement la même chaîne que celle qui a été transmise par read(). DBClass construira la requête SQL pour extraire les données persistantes de la base de données, en utilisant les critères transmis à read(). Cela s'explique par le fait que nous ne voulons pas que le client de DBClass ait besoin de connaître la structure interne de la base de données pour créer une requête valide. Cette connaissance est encapsulée dans la classe DBClass.

Diagramme détaillé dans le contenu.

JDBC : Mettre à jour

Pour mettre à jour une classe, le client de persistance adresse sa demande à la classe DBClass. Celle-ci extrait les données depuis l'objet PersistentClass donné, puis crée une nouvelle instruction au moyen de l'opération createStatement() de la classe Connection. Une fois l'instruction créée, la mise à jour est exécutée et la base de données est mise à jour avec les nouvelles données de la classe.

Ne pas oublier : C'est la classe DBClass qui "regroupe" l'objet PersistentClass et l'écrit dans la base de données. C'est pourquoi elle doit être extraite de la classe PersistentClass en question avant que ne soit créée l'instruction SQL.

Remarque : Dans le mécanisme ci-dessus, PersistentClass doit fournir des sous-programmes d'accès à toutes les données persistantes afin que la classe DBClass puisse y accéder. Cela permet d'avoir un accès externe à certains attributs persistants qui, autrement, auraient été d'accès privé. C'est le prix à payer pour extraire les informations de persistance de la classe où sont encapsulées les données.

Diagramme détaillé dans le contenu.

JDBC : Supprimer

Pour supprimer une classe, le client de persistance demande à la classe DBClass de supprimer la classe PersistentClass. Celle-ci crée alors une nouvelle instruction au moyen de l'opération createStatement() de la classe Connection. L'instruction est exécutée et les données sont retirées de la base de données.

Dans l'implémentation de cette conception, certaines décisions doivent être prises à propos du mappage de la classe DBClass aux classes persistantes, par exemple avoir une classe DBClass par classe persistante et l'attribuer aux packages appropriés. Ces packages seront dépendants du package java.sql fourni (voir JDBC Documentation API) qui contient les classes de support DriverManager, Connection, Statement et ResultSet.