(Data T ansfe Object) (Data Transfer Object)
Transcription
(Data T ansfe Object) (Data Transfer Object)
Quelques patterns pour la persistance des objets avec DAO Ce support présente des modèles de conception utilisés pour effectuer la persistance des objets Université de Nice Sophia-Antipolis Version 1.13.3 – 19/9/10 Richard Grin R. Grin Plan Il est plus fréquent de changer la façon d’effectuer la persistance que de changer le modèle « métier » Pour faciliter les changements dans la persistance i t il faut f t isoler i l le l plus l possible ibl lle code qui gère la persistance Modèle DTO Modèle DAO Problèmes avancés avec les DAOs Modèle fabrique abstraite DAO page 2 Principe de base R. Grin DAO page 3 R. Grin DAO page 4 DAO La persistance est isolée dans des objets spécifiques, les DAO (Data Access Objects) Sans doute le modèle de conception le plus utilisé dans le monde de la persistance R. Grin DAO page 5 Le modèle de conception DTO (Data T Transfer ansfe Object) R. Grin DAO page 6 1 Utilisation des DTOs avec les DAOs Architecture n-tiers DAOs pour accéder à la base Les DAOs sont situés dans une couche proche de la base de données Le code qui utilise les DAOs est souvent situé sur une autre couche distante Les DTOs (synonyme : Transfert Object, TO) peuvent être utilisés pour transporter les données entre les DAOs et cette autre couche (ou plus généralement entre 2 couches distantes) Affiche des données récupérées dans la base Utilisent les DAOs R. Grin DAO page 7 R. Grin Les appels de méthode distants sont beaucoup plus coûteux que les appels locaux Le coût dépend peu de la quantité de données transférée à chaque appel DAO page 9 Exemple Récupérer les données sur une facture, ses lignes de factures et les produits concernés Plusieurs appels de méthodes sont nécessaires pour récupérer tous les objets (l’en-tête de la facture les lignes et les produits) facture, DAO Des données provenant d’un ou de plusieurs objets distants doivent être récupérées pour faire un traitement métier Ces données ne peuvent être récupérées que par de nombreux appels de méthodes (coûteux puisque appels à distance) R. Grin DAO page 10 Exemple des EJB entités, version 2 R. Grin page 8 Le problème à résoudre Un fait important R. Grin DAO page 11 Les DTO ont surtout été utiles avec les versions 1 et 2 des EJB entités (objets qui représentaient les données d’une base de données) Les EJB entités n’étaient pas transportables sur le réseau (car ils ne pouvaient fonctionner correctement qu’avec l’aide d’un serveur d’applications, logiciel complexe situé sur la machine « serveur ») R. Grin DAO page 12 2 La solution DTO Exemple d’un EJB entité, version 2 Pour avoir les nom, prénom, salaire et lieu de travail d’un employé, EJB entité de la version 2, il fallait utiliser les accesseurs de la classe EJB (getNom, getPrenom, getSalaire, getLieu) et donc plusieurs appels distants étaient nécessaires Les objets « entités » de EJB 3 sont transportables sur le réseau (entités détachées de JPA) et les DTO sont beaucoup moins utiles dans ce cas R. Grin R. Grin DAO page 13 Le client (celui qui veut les données pour faire le traitement) demande un objet qui contient toutes les valeurs dont il a besoin Cet objet, un Data Transfert Object (DTO), est construit sur le site distant et passé en une seule fois au client Un DTO contient l’état d’un objet (ou de plusieurs), mais pas son comportement ; il est donc facilement transportable sur le réseau (il est sérialisé ; voir cours sur les entréessorties) Exemple DAO page 14 Pour découpler 2 parties On reprend l’exemple précédent de la facture Un DTO qui contient toutes les données (en-tête de facture, lignes de facture, produit) est créé sur la couche distante Il est passé en un seul appel de méthode (getDtoFacture() par exemple) au code qui a besoin de ces informations Le code peut alors interroger le DTO en local R. Grin DAO page 15 Il est envisageable d’utiliser une « couche DTO » pour découpler 2 parties de l’application et mieux les isoler, mais ça n’est souvent pas recommandable, surtout si les DTO ne servent pas à transporter des données à distance Le découplage ne justifierait le plus souvent pas la complication qui en résulterait Inutile de compliquer l’architecture avec des DTOs si l’application est locale (pas distribuée) R. Grin DAO page 16 DTO pour modifier Un DTO peut aussi être utilisé pour modifier un ou plusieurs objets distants (ou les données de la base de données) : n le DTO est créé ou modifié sur une couche de l’application n il est passé à une couche distante qui utilise ses données pour modifier un ou plusieurs objets distants (ou la base de données) R. Grin DAO page 17 Le modèle de conception DAO (Data Access Object) R. Grin DAO page 18 3 Le problème à résoudre La solution Le code pour la persistance varie beaucoup n avec le type de stockage (BD relationnelles, BD objet, fichiers simples, etc.) n avec les implémentations et les différentes versions i d des ffournisseurs i d de SGBD n pour améliorer les performances Si les ordres de persistance sont imbriqués avec le code « métier », il est difficile de changer ce code R. Grin DAO page 19 Encapsuler le code lié à la persistance des données dans des objets DAO dont l’interface est indépendante du type de persistance Le reste de l’application utilise les DAOs pour gérer la persistance, en utilisant cette interface abstraite, indépendante du support de persistance, contenant par exemple la méthode Employe getEmploye(int matricule) Seuls les DAOs devront être modifiés si la façon d’effectuer la persistance est modifiée R. Grin Quand l’application a besoin d’effectuer une opération liée à la persistance d’un objet, elle fait appel à un objet DAO à qui elle passe les informations nécessaires pour effectuer l’opération Chaque classe d’objet métier a son propre type de DAO (DAOEmploye, DAODepartement, …) Mais le même objet DAO peut être utilisé pour tous les objets d’une classe d’objets métier Exemple : une instance de DAOEmploye peut servir pour tous les employés DAO page 21 Plus facile de modifier le code qui gère la persistance (changement de SGBD ou même de modèle de données) Factorise le code d’accès à la base de données Plus Pl facile f il pour le l spécialiste é i li t d des BD d’optimiser les accès (ils n’ont pas à parcourir toute l’application pour examiner les ordres SQL) R. Grin Les DAOs sont placés dans la couche dite « d’accès aux données » qui est souvent sur une autre machine que la couche des objets métiers Les échanges de messages entre les DAOs et les objets métiers engendrent donc souvent des appels distants et des DTO peuvent donc être utilisés pour ces échanges DAO DAO page 22 CRUD Emplacement des DAOs R. Grin page 20 Utilité des DAOs DAO R. Grin DAO page 23 Cet acronyme désigne les opérations de base de la persistance : create, retrieve, update et delete Ces 4 opérations de base sont implémentées dans un DAO R. Grin DAO page 24 4 create - paramètres CRUD Create pour créer une nouvelle entité dans la base Retrieve pour retrouver une ou plusieurs entités de la base Update pour modifier une entité de la base Delete pour supprimer une entité de la base Plusieurs variantes pour les signatures de ces méthodes dans les DAOs R. Grin DAO page 25 create(int id, String nom,…) n Le type retour peut être n void (la variante la plus utilisée) n boolean pour indiquer si la création a pu avoir lieu (on peut utiliser une exception à la place) n l’identificateur de l’entité ajoutée (utile si la clé primaire est générée automatiquement dans la base de données) n un objet métier (s’il est transportable) ou un DTO correspondant à l’entité ajoutée R. Grin DAO page 27 create Comparaison des variantes (2) La variante avec objet métier ne convient que si l’objet métier est facilement transportable et a ses propriétés accessibles par la couche de persistance (mais on peut aussi utiliser la réflexivité si elles ne sont pas accessibles) Elle peut être pratique et performante dans les cas où elle est applicable, et elle convient bien lorsque l’API de persistance représente les entités persistantes par des objets (ORM et SGBDOO étudiés plus loin dans le cours) R. Grin Mapping objet-relationnel DAO page 29 par un DTO : create(DTOArticle dto) n par un objet métier : create(Article article) R. Grin DAO page 26 create Comparaison des variantes (1) create – type retour Prend en paramètre l’état de la nouvelle entité Cet état peut être donné n par une série de paramètres : (Ces remarques sont aussi valables pour les autres opérations de type CRUD) Les variantes qui passent les différentes valeurs individuellement sont les plus souples Lorsque les DTOs sont utilisées par ailleurs, les variantes avec DTO sont souvent rencontrées R. Grin DAO page 28 Exemple de code JDBC pour create private String insert = variable d’instance "insert into STYLO (ref, nom, prix, couleur) values(?, ?, ?, ?)"; ... méthode create PreparedStatement ps = connexion.prepareStatement(insert); ps.setString(1, reference); ps.setString(2, nom); ps.setString(3, couleur); ps.setBigDecimal(4, prix); ps.executeUpdate(); R. Grin DAO page 30 5 Exemples de finders retrieve 3 types de méthode, suivant qu’elle retourne n un seul objet n une collection d’objets n une valeur calculée à p partir de p plusieurs entités (agrégation ; un total par exemple) Une méthode (ou un objet) qui retourne des données de la base de données est souvent appelée finder R. Grin DAO page 31 Il reçoit en paramètre un identificateur de l’entité cherchée Il retourne un objet métier qui correspond aux données identifiées, ou un DTO qui contient ces données Il retourne null si rien n’a été trouvé (rarement une exception) DAO R. Grin page 33 Il reçoit en paramètre le critère de sélection, sous une forme quelconque n objet ou valeurs « critère de sélection » n objet « exemple » (à la « query by example ») Le type retour peut être très divers : n ResultSet n RowSet n Collection (Collection, List, Set,…) d’objets métier ou de DTOs n tableau (rare) R. Grin DAO page 34 Finder qui retourne une valeur calculée Si le critère de la requête n’est vérifiée par aucune valeur, le finder doit retourner une « collection » (collection, resultset, rowset ou tableau) vide Retourner la valeur null obligerait à un cas particulier pour le traitement de la valeur retournée (« if (result == null) » avant une boucle qui parcourt le résultat) DAO page 32 Résultat vide R. Grin DAO Finder qui retourne une collection Finder qui retourne un objet R. Grin On trouvera le plus souvent n une méthode findById(id) (ou d’un nom semblable…) qui retrouve une entité en donnant son identificateur dans la base n une méthode findAll() qui retrouve toutes les entités du type géré par le DAO Mais on trouvera aussi des finders qui cherchent suivant des critères quelconques ou suivant des critères bien précis (ces finders dépendent des traitements métier) page 35 Les valeurs calculées à partir des données de plusieurs entités peuvent s’obtenir à partir d’objets chargés en mémoire Mais il p peut être p préférable de ne p pas créer les objets et d’utiliser un DAO pour interroger directement la base de données qui est optimisée pour ce type de requête Exemple : méthode getTotalSalaire() de DaoEmploye, qui renvoie le total des salaires des employés R. Grin DAO page 36 6 update delete Variantes pour les paramètres : n identificateur de l’entité à supprimer dans la base n l’objet métier (ou un DTO) correspondant à l’entité à supprimer pp dans la base Variantes pour le type retour : n void n boolean pour indiquer si la suppression a pu avoir lieu (exception sans doute préférable) Des variantes diverses pour les paramètres : n identificateur + valeurs (plusieurs paramètres pour les valeurs ou un seul DTO) n l’objet métier dont on veut sauvegarder les modifications (nécessite un accès public aux valeurs qui seront modifiées) Le type retour peut être n void n boolean pour indiquer si la modification a pu avoir lieu (exception sans doute préférable) R. Grin R. Grin DAO page 37 page 38 2 stratégies d’utilisation des DAOs Autres méthodes des DAOs Outre les opérations CRUD, les DAO peuvent aussi implémenter des méthodes spécifiques au modèle métier de l’application Le plus souvent ce sont des variantes de l’opération « retrieve » Par exemple une méthode qui renvoie les candidats qui ont une mention à un examen 1. R. Grin R. Grin DAO DAO page 39 2 2. Chaque objet métier a une référence à un DAO et l’utilise pour sa propre persistance. Le programme qui manipule les objets métier ne connaît pas les DAOs. Le programme qui manipule les objets métier utilise directement les DAOs. Les objets métier n’ont pas de référence à un DAO (stratégie sans doute la plus fréquemment utilisée). DAO page 40 Exemple de code Stratégie 1 Les programmes qui manipulent les objets métier ne sont pas modifiés par rapport à un programme qui n’utilise pas de DAO Seuls les objets métier connaissent leur DAO Les L objets bj métier éi d doivent i avoir i une référence éfé vers le DAO qu’ils utilisent Cette référence peut être obtenue par une méthode static de la classe DAO (ce qui peut permettre de partager un DAO entre tous les objets métier d’une même classe) class Stylo { private StyloDAO dao; ou un DTO, ou ... les valeurs des public void sauvegardeToi() { propriétés du dao = getDAO(); stylo dao.insertOrUpdate(this); dao. se t pdate(t s); } private StyloDAO getDAO() { if (dao == null) Pour simplifier, on ne StyloDAO.getDAO(); tient pas compte des return dao; exceptions } R. Grin R. Grin DAO page 41 DAO page 42 7 En dehors de la classe Stylo Stratégie 2 // Travail avec un stylo (création, // modification,…) ... // Sauvegarde du stylo stylo.sauvegardeToi(); t l d T i() On rencontre le plus souvent la stratégie 2 On perd sans doute de la pureté de la programmation objet mais l’avantage est que les objets métiers ne sont pas encombrés du code pour la persistance, ce qui facilite les tests et permet une meilleure séparation du service de persistance Le DAO n’est pas visible en dehors de la classe Stylo R. Grin DAO page 43 R. Grin Exemple de code Stylo stylo = new Stylo(145, "Marker", "noir ", ...); StyloDAO styloDAO = StyloDAO.getDAO(); styloDao.create(stylo); . . . Stylo stylo = styloDAO.findById(1234); stylo.setPrix(45); styloDAO.update(stylo); List<Stylo> l = styloDAO.findAll(); En dehors de // ou styloDAO = new StyloDAO() la classe Stylo StyloDAO styloDAO = StyloDAO.getDAO(); int idStylo = styloDAO.create("Marker", "noir ", 120 120,...); ); . . . Stylo stylo = styloDAO.findById(idStylo); styloDAO.update(idStylo, ...); List<Stylo> l = styloDAO.findAll(); Le code de la classe Stylo n’utilise aucun DAO DAO Le code de la classe Stylo n’utilise aucun DAO page 45 Cette image (et les suivantes) sont extraites du « Core J2EE Pattern Catalog » de Sun DAO R. Grin DAO page 46 Diagramme de séquences Diagramme de classes (avec utilisation de TO) R. Grin page 44 Exemple de code (variante) En dehors de la classe Stylo R. Grin DAO page 47 Modification de plusieurs attributs persistants en utilisant un DTO : création du DAO, puis récupération des valeurs actuelles, R. Grinmodification de ces valeurs DAO page 48 puis 8 Problèmes abordés DAO et exceptions DAO et connexions DAO et transactions DAO et objets composés DAO et duplication des entités Problèmes avancés sur les DAO R. Grin DAO page 49 R. Grin Indépendance vis-à-vis du type de persistance Il n’est pas simple de rendre l’utilisation des DAOs totalement indépendante du type de persistance Ainsi il faut fa t cacher les ttypes pes d’e d’exceptions ceptions particuliers aux types de persistance (SQLException par exemple), et les façons différentes de se connecter aux BD R. Grin DAO page 51 DAO et exceptions (2) Pour cela, on crée une ou plusieurs classes d’exception indépendantes du type de persistance, désignons-les par DaoException (ou DataAccessException) Les méthodes des DAO attrapent les exceptions particulières, par exemple les SQLException, et relancent des DaoException (auxquels sont chaînées les exceptions d’origine pour faciliter la mise au point) DAO page 50 DAO et exceptions (1) Les méthodes des DAO peuvent lancer des exceptions lorsqu’elles effectuent des opérations d’entrées-sorties Les exceptions ne doivent pas être liées à un type de DAO particulier si on veut pouvoir changer facilement de type de DAO R. Grin DAO page 52 DAO et gestion des connexions (1) R. Grin DAO page 53 Une connexion peut être ouverte au début des méthodes du DAO, et fermée à la fin des méthodes Mais cette stratégie va coûter cher si un pool de connexions n’est n est pas utilisé utilisé, et elle manque totalement de souplesse R. Grin DAO page 54 9 DAO et gestion des connexions (2) Il est préférable que les connexions puissent être ouvertes par les clients des DAOs s’ils le souhaitent et puissent ainsi couvrir plusieurs appels de méthodes Pour cela il faut ajouter au code du DAO une méthode setConnection qui va permettre au client de passer une connexion ouverte au DAO R. Grin DAO page 55 Exemple schématique JDBC - client Exemple schématique JDBC - DAO public class StyloDao { private Connection conn; public void setConnection(Connection c) { this.conn = c; } public long create( create(...) ) { PreparedStatement pstmt = conn.prepareStatement(...); pstmt.setString(...); ... pstmt.executeUpdate(); } R. Grin Chaque API de persistance a son propre type de persistance Il faut cacher ce type pour pouvoir changer facilement de type de persistance (un des buts des DAOs) R. Grin R. Grin page 57 R. Grin R. Grin page 59 page 58 Une instance d’un sous-type de Connexion peut être fournie aux clients des DAOs (ou aux DAOs) par la fabrique abstraite de DAOs (méthode « getConnexion », voir section suivante) comme les DAOs suivante), Les clients peuvent ensuite passer cette instance de Connexion aux DAOs ; il suffit d’ajouter aux DAOs une méthode setConnexion(Connexion c) Une solution est de créer une classe abstraite, (ou interface), nommée Connexion par exemple Les connexions concrètes sont implémentées par des classes filles de Connexion, Conne ion qui encapsulent la connexion concrète (que ce soit une Connection pour JDBC ou un EntityManager pour JPA, ou tout autre type de connexion) DAO DAO Obtenir une connexion Cacher le type de connexion (2) page 56 Cacher le type de connexion (1) // Ouverture de la connexion par le client Connection conn = ... ; // Il la passe aux DAOs daoStylo.setConnection(conn); d R daoRamette.setConnection(conn); tt tC ti ( ) ... daoStylo.create(...); daoRamette.update(...); // Le client peut gérer la transaction conn.commit(); DAO DAO DAO page 60 10 Méthodes pour les connexions La classe Connexion contient des méthodes pour ouvrir et fermer la connexion, pour gérer les transactions, permettant ainsi aux clients des DAOs de gérer les connexions et les transactions R. Grin DAO page 61 Gestion des transactions Qui gère les transactions ? Un DAO pourrait démarrer et terminer luimême les transactions à chaque méthode Cependant il n’est pas rare de vouloir inclure un ou plusieurs appels de méthodes de DAOs dans une seule transaction Les clients du DAO doivent donc pouvoir gérer les transactions (début, fin avec commit ou rollback) s’ils le souhaitent Le DAO utilise alors la transaction en cours si elle existe R. Grin Si la manipulation des connexions décrites précédemment est utilisée, les clients peuvent gérer les transactions par l’intermédiaire des connexions dont ils ont la maîtrise Il suffit d’ajouter des méthodes du type beginTransaction, commit, rollback au type Connexion (ces méthodes agissant en interne sur les connexion concrètes encapsulées, par exemple Connection ou EntityManager) R. Grin R. Grin page 63 Informations pour les connexions (2) Comment le code récupère-t-il les informations nécessaires pour se connecter à la base de données ? Le plus souvent ces informations sont contenues dans un fichier de propriétés (ou un autre type de fichier) dont l’emplacement est connu (soit un emplacement par défaut, soit un emplacement passé en paramètre au code qui doit ouvrir la connexion) R. Grin R. Grin page 65 DAO page 64 Informations pour les connexions (3) L’utilisation d’un fichier de propriétés a l’avantage de permettre de changer ces informations sans recompiler l’application Si les informations ne sont connues que pendant l’exécution, il est possible d’utiliser une map dont les éléments sont les noms et les valeurs des propriétés de connexion ; cette map peut être remplie pendant l’exécution, et passée ensuite au code qui a besoin de l’information DAO page 62 Informations pour les connexions (1) DAO DAO Dans le cas où les DAOs sont créés par des fabriques (voir suite de ce support), les informations de connexion (souvent encapsulées dans les Connexion) peuvent êt passées être é aux ((ou llues par lles)) ffabriques bi qui les passent ensuite aux DAOs DAO page 66 11 Gestion des connexions et transactions en environnement géré DAO et objets composés Un exemple du problème : pour une facture, le dao pour les factures doit-il retourner immédiatement les lignes de la facture ? La réponse dépend du contexte On peut ainsi être amené à écrire dans le DAOFacture 2 méthodes pour récupérer une facture, ou au moins une méthode avec un paramètre indiquant ce que l’on veut retourner immédiatement (l’en-tête de facture seule ou l’en-tête avec les lignes) Les environnements d’entreprise ou les frameworks de persistance (Java EE, Hibernate, Spring ou autre) gèrent les connexions aux bases, bases dont les propriétés sont encapsulées dans des sources de données (javax.sql.DataSource ; étudié dans la partie JDBC avancé de ce cours) Ils offrent aussi des facilités pour gérer les transactions (pas étudié dans ce cours) R. Grin DAO page 67 R. Grin Éviter les duplications DAO page 68 Conclusion Si le DAO n’utilise pas un framework qui gère le problème (comme JPA par exemple), le DAO devra éviter la création en mémoire de 2 objets entités qui représentent les mêmes d données é d dans lla b base d de d données é ((voir i cours sur le mapping objet-relationnel) R. Grin DAO page 69 La persistance des objets confronte le développeur à de multiples problèmes avancés du genre de ceux que nous venons de voir C’est pour cela que, le plus souvent, avec ou sans DAO, il vaut mieux utiliser un framework de type JPA (ou des frameworks plus globaux comme J2EE ou Spring) qui règle une grande partie de ces problèmes (mais pas tous…) R. Grin DAO page 70 Création des DAOs Souvent les clients des DAOs ne créent pas les DAOs en utilisant leur constructeur mais utilisent plutôt les modèles de conception « fabrique » ou « fabrique abstraite » L’utilisation ’ de ces ffabriques améliore é l’indépendance vis-à-vis du type de persistance Le modèle de conception « fabrique fab iq e abstraite abst aite » R. Grin DAO page 71 R. Grin DAO page 72 12 Un cas d’utilisation Avec un constructeur Une application fonctionne sur un ordinateur portable L’application peut utiliser une base locale MySQL si l’ordinateur n’est pas connecté à Internet, ou une base Oracle distante s’il est connecté Comment récupérer le bon DAO pour chaque classe métier, par exemple, un DaoStyloMySQL ou un DaoStyloOracle suivant le cas ? R. Grin DAO page 73 Le code DaoStylo dao = new DaoStyloOracle(); fixe le type de DAO créé Il devra être modifié si on veut un autre type Il faudra prévoir un « if » selon le type de DAO souhaité pour tous les codes qui créeront un DAO ! et modifier le code source et recompiler si on ajoute un nouveau type de DAO !! R. Grin Pattern « fabrique » pour récupérer les DAO DAO page 74 Avec une fabrique Le pattern « fabrique » (factory) permet de créer des instances en cachant le type concret des instances créées R. Grin DAO page 75 DaoStylo dao = fabriqueDaoStylo.getDao(); dao sera du type DaoStyloOracle ou DaoStyloMySQL selon le cas DaoStylo est une interface implémentée par les classes concrètes de DAO DaoStyloOracle et DaoStyloMySQL R. Grin DAO page 76 Schéma du code d’une fabrique Fixer le type de DAO Pour fixer le type de DAO renvoyé (ou pour le modifier par la suite) : fabriqueDaoStylo .setTypeDao(typeDao); typeDao peut, par exemple, être déterminé en testant si l’ordinateur est connecté ou non à Internet, au démarrage de l’application et à d’autre moments clés de l’exécution ; son type Java est souvent une énumération public class FabriqueDaoStylo { private TypeDao typeDao; public void setTypeDao(TypeDao typeDao) { this.typeDao = typeDao; } public DaoStylo getDao() { switch (typeDao) { case TypeDao.MYSQL: return new DaoStyloMySQL(); case TypeDao.ORACLE: ... R. Grin R. Grin DAO page 77 DAO page 78 13 Fabrique abstraite Fabrique abstraite Si on veut changer de base de données, le type de DAO doit être fixé pour toutes les fabriques de DAOs Le pattern « fabrique abstraite » permet de changer plus facilement de base de données : en une seule ligne de code tous les DAOs peuvent être remplacés par des DAOs adaptés à la nouvelle base de données choisie R. Grin R. Grin DAO page 79 Le code qui suit est un exemple schématique de l’utilisation du pattern DAO, avec le pattern fabrique abstraite (inspiré fortement d’un exemple donné par Sun) Il utilise le pattern DTO/TO exposé dans la 1ère partie de ce cours mais on peut très bien s’en passer si les objets persistants peuvent être transportés entre les différentes couches d’une application (par exemple, pour une application locale, ou en utilisant les objets « détachés » de JPA ou de Hibernate) DAO page 81 Avec une seule ligne de code, la bonne fabrique de DAOs est récupérée, associée au bon type de persistance DAO page 80 Seule ligne de code pour changer de type de persistance. Tout le reste est DaoFactory.setTypeDao( DaoFactory.TypeDao.MYSQL); indépendant de ce type DaoFactory daoFactory = DaoFactory.getDaoFactory(); styloDao = daoFactory.getStyloDao(); // crée é un nouveau stylo t l d dans l la b base int styloNo = styloDao.create(...); // Trouve un stylo StyloTo styloTo = styloDao.find(...); // Modifie des valeurs du DTO styloTo.setPrix(125); // Modifie le stylo dans la base styloDao.update(styloTo); R. Grin Code client (1) DAO page 82 Fabrique abstraite – 1 DAO Code client (2) La fabrique abstraite // Supprime un stylo de la base styloDao.delete(styloNo); // Trouve tous les stylos d’une marque // Utilise un stylo « exemple » de ce // q que l’on cherche StyloTo styloEx = new StyloTo(); styloEx.setMarque("Marker"); Collection<StyloTo> listeStylos = styloDao.find(styloEx); Les fabriques concrètes Caché Les DAOs créés ... R. Grin Le type abstrait Code pour fabrique abstraite R. Grin Une fabrique abstraite est un type abstrait qui permet de cacher les types réels d’un ensemble de fabriques concrètes Chaque fabrique concrète fournit tous les DAOs (DAOStylo, (DAOStylo DAORamette,…) DAORamette ) associés à un type de persistance (DAOStyloOracle, DAORametteOracle,…) DAO page 83 R. Grin DAO Type abstrait de DAO page 84 14 Fabrique abstraite – 1 source de données Fabrique abstraite – schéma global Une fabrique concrète crée tous les DAOs associés à une source de données R. Grin DAO page 85 R. Grin Après le code « client », on va présenter le code de la fabrique abstraite, des fabriques concrètes et des DAOs (là encore l’utilisation des DTOs n’est pas indispensable) R. Grin DAO page 87 public abstract class DaoFactory { public enum TypeFabrique {MYSQL, ORACLE}; private static TypeFabrique typeFabrique; public abstract StyloDao getStyloDao(); public abstract FactureDao getFactureDao(); ... public static DaoFactory setTypeDao( TypeFabrique unTypeFabrique) { typeFabrique = unTypeFabrique; } R. Grin La fabrique abstraite (2) } DAO DAO page 88 Une fabrique concrète public static DaoFactory getDaoFactory() { switch (typeFabrique) { case MYSQL: return new MysqlDaoFactory(); case ORACLE: return new OracleDaoFactory(); default: ... ; // erreur } } R. Grin page 86 La fabrique abstraite (1) Code pour fabrique abstraite DAO page 89 public class MySQLDaoFactory extends DaoFactory { @Override public StyloDao getStyloDao() { return new MySQLStyloDao(); } @Override public FactureDao getFactureDao() { return new MySQLFactureDao(); } ... } R. Grin DAO page 90 15 Interface des DAO pour Stylo DAO concret pour Stylo public interface StyloDao { public int insert(...); public boolean delete(...); identificateur public StyloTo find(...); public boolean update( update(...); ); public Collection<StyloTo> findAll(...); public Collection<StyloTo> find(...); ... } objet exemple import java.sql.*; public class MySQLStyloDao implements StyloDao { public MySQLStyloDao() { ... } public int insert(…) p ( ) { ... } public boolean delete(…) { ... } public StyloTo find(…) { ... } public boolean update(...); public Collection<StyloTo> findAll(...); ... } R. Grin R. Grin DAO page 91 TO pour Stylo DAO page 93 Si on veut ajouter un nouveau type de DAO (par exemple, un DAO pour un autre article), il faut modifier le code de toutes les fabriques abstraite et concrètes pour ajouter la méthode éth d quii renvoie i ce nouveau DAO R. Grin DAO et EJB DAO DAO page 94 Bibliographie Dans les applications construites selon la spécification EJB, les DAOs seront le plus souvent des beans sessions sans état (@Stateless) avec des contextes de persistance i t limités li ité à une ttransaction ti (voir ( i cours sur JPA) R. Grin page 92 Inconvénient de ce pattern import java.io.Serializable; public class StyloTo implements Serializable { private String reference; indispensable pour être private String name; transporté d’une couche ... à une autre t // Accesseurs et modificateurs public String getReference() {...} public void setReference(String ref) {...} ... } R. Grin DAO Patterns of Entreprise Application Architecture de Martin Fowler – Addison Wesley Présentation du pattern DAO et implémentation en Java, par Sun : http://java.sun.com/blueprints/corej2eepattern s/Patterns/DataAccessObject.html page 95 R. Grin DAO page 96 16