I. Exemple d'application classique▲
Prenons en exemple une application très simple de gestion de comptes bancaires. Les données sont stockées dans une base composée de ces trois tables :
|
|
Pour voir la structure des tables en détail, Cliquez ici.
Dans la feuille ci-contre, l'utilisateur demande l'affichage des comptes d'un client en entrant l'identifiant du client, puis en cliquant sur le bouton "Afficher". |
|
Voici une façon simple de gérer l'affichage des comptes dans la datagrid, sur l'évènement Click() du bouton :
Si le contenu du champ texte est numérique, une connexion est créée, les comptes sont récupérés dans un recordset qui devient la source de la datagrid.
L'affichage des comptes d'une personne peut être scindé en trois parties distinctes :
- l'interface utilisateur ;
- la logique de l'application : vérification de l'identifiant saisi et lecture du compte dans la base ;
- connexion à la base de données et ouverture d'un recordset.
Le code source ci-dessus contient donc ces trois parties, alors qu'elles devraient être clairement distinctes. Cela permettrait de réutiliser le code qui crée une connexion à la base de données, et celui qui retrouve les comptes bancaires d'une personne. De façon générale, il vaut mieux programmer une application en séparant ces 3 fonctions : présentation, logique de l'application, et stockage des données.
II. Rôle de chacune des couches▲
La couche présentation :
- affiche les données ;
- envoie les demandes de l'utilisateur à la couche métier pour qu'elle les effectue ;
- reçoit les résultats renvoyés par la couche métier et les affiche.
La couche métier (logique de l'application) :
- reçoit et analyse les demandes de l'utilisateur ;
- retrouve et modifie les données via la couche données ;
- renvoie les résultats à la couche présentation.
La couche données :
- modifie les données ;
- récupère les données ;
- assure la sécurité et l'intégrité des données.
III. Avantages de cette architecture▲
Séparer l'application en trois couches a de nombreux avantages, en voici une liste non exhaustive :
- la gestion des données et la logique métier peuvent être indépendantes du type d'interface :
La logique de l'application et ses données pourront être utilisées par une interface Windows ou par un site ASP par exemple ; - les couches métier et données sont encapsulées :
ces couches assurent l'intégrité des données en analysant les demandes du client avant de les effectuer, et on gagne donc en robustesse. Pendant la réalisation de la couche métier, on peut se concentrer sur la logique de l'application et l'intégrité des données, sans se soucier de la présentation, et la maintenance en devient plus facile ; -
les couches métier et données peuvent être placées sur un serveur ou chacune sur un serveur distinct.
- La couche présentation n'accédant pas directement aux données, la configuration de l'accès aux données ne se fait alors que sur le serveur où réside la couche données.
- Si la couche métier ou celle des données est modifiée, il n'y a pas de réinstallation à faire sur les postes clients.
IV. Exemple d'architecture à trois couches▲
Nous allons reprendre l'application de gestion de comptes bancaires, qui nous avait servi d'exemple.
La couche présentation sera un EXE standard, et les couches métier et données seront chacune une Dll ActiveX. Commençons par la couche des données.
IV-A. Couche données▲
Cette couche aura donc la forme d'une dll ActiveX. Pour créer ce type de projet, cliquez sur le menu Fichier -> Nouveau projet, puis sur DLL ActiveX. Allez dans les propriétés du projet et saisissez "Data" pour le nom du projet. La classe Class1 a été créée par défaut, renommez-la en clsData. Ce sera la seule classe contenue dans cette couche.
La classe clsData doit pouvoir : ouvrir une connexion à la base de données, et renvoyer un recordset déconnecté à partir d'une requête passée en paramètre.
Nous avons tout d'abord une énumération qui représente les numéros d'erreurs qui peuvent être créées par cette classe. Ces erreurs peuvent être signalées à la couche métier. La procédure Class_Initialize() est exécutée à l'initialisation de la classe. C'est à ce niveau que nous initialisons les variables qui contiennent les paramètres de notre connexion.
La fonction CreeConnexion() instancie un objet ADODB.Connection, se connecte à la base de données et renvoie l'objet instancié.
La fonction CreeRecordset() crée puis renvoie un recordset déconnecté, le code sql de la requête devant être passé en paramètre.
Nous renvoyons un recordset déconnecté, car un recordset connecté qui est transféré sur le réseau, conserve avec lui toutes les informations nécessaires pour rester lié à sa source de données.
Pour que le recordset soit déconnecté, vous devez :
- donner à la propriété CursorLocation la valeur adUseClient, et ceci avant d'ouvrir le recordset. Ainsi le curseur sera géré du côté client ;
- donner à la propriété ActiveConnection la valeur Nothing, après l'ouverture du recordset. Cela a pour effet de déconnecter le recordset de sa source de données.
En utilisant cette méthode, le recordset est transféré du serveur vers le client, morceau par morceau. Il faut donc plusieurs allers-retours entre le serveur et le client pour que le recordset soit totalement transféré, ce qui n'est pas l'idéal. Ceci peut-être encore amélioré en utilisant les composants RDS pour accéder aux données. Pour plus d'informations sur RDS, voir la documentation sur MSDN.
Ici la valeur choisie pour le "locktype" du recordset est adLockReadOnly, parce que les enregistrements n'ont pas besoin d'être modifiables par le client.
IV-B. Couche métier▲
Nous allons créer cette couche sous la forme d'une autre dll ActiveX. Tout d'abord le projet Data doit avoir été compilé. Puis sans fermer le projet, cliquez sur le menu Fichier -> Ajouter un projet, et sélectionnez DLL ActiveX. Renommez le nouveau projet en "Rules". La couche métier va utiliser la couche données, donc l'activeX "Data" doit être ajouté dans les références du projet.
La couche données contiendra deux classes. La classe clsServices qui nous fournira les comptes de quelqu'un, ainsi que les opérations d'un compte. Et clsCompte qui nous permettra de lire ou de modifier un compte. Voici le code source de la classe clsServices :
Ces deux méthodes renvoient un recordset déconnecté. À ce niveau on se connecte à la base de données, mais l'on ne sait pas comment. Le type de base de données, son emplacement, la manière de se connecter, le mot de passe s'il y en a un, sont gérés dans la couche des données.
Voici la classe clsCompte :
Ceci n'est qu'un aperçu de ce que pourrait être la classe clsCompte dans une application complète. Elle doit contenir toutes les règles de fonctionnement relatives à un compte. Les valeurs des champs ne sont modifiables que par l'intermédiaire des propriétés de la classe, qui contrôlent leur modification. Par exemple, il est interdit de modifier le numéro du compte si celui-ci a déjà été créé.
Un compte est lu avec la méthode Load(). La méthode Save() permet d'ajouter un nouveau compte ou d'enregistrer les modifications effectuées sur un compte existant.
IV-C. Couche présentation▲
À ce stade nous n'avons plus qu'à programmer l'interface, qui affichera les données et effectuera les commandes demandées par l'utilisateur, et ceci simplement en manipulant les objets de la couche métier.
Pour créer cette couche, ajoutez un projet de type Exe Standard. Ajoutez l'activeX Rules dans ses références.
Voici ce que devient notre code source du premier chapitre, qui affichait les comptes d'une personne dans une datagrid :
Vous pouvez télécharger les sources.