(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

Documents pareils