Les Modèles de conception pour la Couche d'Accès aux Données
J'ai une application qui utilise une base de données (MongoDB) pour stocker des informations. Dans le passé, j'ai utilisé une classe de méthodes statiques pour enregistrer et récupérer des données, mais depuis, j'ai réalisé que ce n'est pas très orientée objet-ish ou dans l'avenir.
Même s'il est très peu probable que je vais changer de base de données, je préférerais quelque chose qui ne pas m'attacher trop fortement à Mongo. Je tiens également à être en mesure de mettre en cache les résultats avec l'option d'actualisation de l'objet mis en cache à partir de la base de données, mais ce n'est pas indispensable et peut être fait dans un autre endroit.
J'ai regardé objets d'accès aux données, mais ils ne semblent pas très bien défini et je ne trouve pas de bons exemples de mise en œuvre (En Java ou un langage similaire). J'ai aussi beaucoup de une hors des cas tels que la recherche de noms d'utilisateur pour la saisie semi-automatique qui ne semblent pas bien adapté et rendrait le DAO grand et gonflé.
Existe-il des modèles de conception qui permettrait de faciliter l'obtention et l'enregistrement des objets sans trop de base de données spécifique? De bons exemples de mise en œuvre serait utile (de préférence en Java).
OriginalL'auteur user2248702 | 2014-12-31
Vous devez vous connecter pour publier un commentaire.
Bien, l'approche commune pour le stockage de données en java est, comme vous l'avez remarqué, pas du tout très orienté-objet. C'est en soi ni bonne ni mauvaise: "l'objet-orienté" n'est ni un avantage, ni inconvénient, c'est juste l'un des nombreux paradigmes, qui aide parfois avec une bonne conception de l'architecture (et parfois pas).
La raison DAOs en java ne sont pas généralement orientée objet est exactement ce que vous voulez obtenir de détendre votre dépendance sur la base de données spécifique. Mieux conçu langue, qui a permis à l'héritage multiple, c', ou bien sûr, peut être fait très élégante dans une méthode orientée objet, mais avec java, il semble juste être plus d'ennuis que cela vaut la peine.
Dans un sens plus large, la non-OO approche permet de découpler au niveau de l'application des données de la manière dont elles sont stockées. C'est plus de la (non) la dépendance sur les spécificités d'une base de données particulière, mais aussi le stockage des schémas, ce qui est particulièrement important lors de l'utilisation de bases de données relationnelles (ne me lancez pas sur ORM): vous pouvez avoir un schéma relationnel parfaitement traduit dans l'application OO modèle par votre DAO.
Donc, ce que la plupart des DAOs sont en java sont aujourd'hui essentiellement ce que vous avez mentionné dans le début des classes, plein de méthodes statiques. Une différence est que, au lieu de faire toutes les méthodes statiques, il est préférable d'avoir un seul statique de la "méthode de fabrique" (probablement, dans une classe différente), qui renvoie un (singleton) instance de votre DAO, qui implémente une interface particulière, utilisée par le code de l'application pour accéder à la base de données:
Pourquoi le faire de cette façon, par opposition à des méthodes statiques? Eh bien, que si vous décidez de passer à une autre base de données? Naturellement, vous devez créer une nouvelle classe DAO, la mise en œuvre de la logique de votre stockage. Si vous avez été en utilisant des méthodes statiques, vous avez maintenant à passer à travers tout votre code, l'accès à la DAO et de la modifier pour l'utilisation de votre nouvelle classe, non? Ce pourrait être une grande douleur. Et si ensuite vous changez d'avis et que vous voulez revenir à l'ancienne db?
Avec cette approche, tout ce que vous devez faire est de modifier le
GreatDAOFactory.getDAO()
et la faire de créer une instance d'une autre classe, et tout le code de votre application sera à l'aide de la nouvelle base de données sans aucune modification.Dans la vraie vie, cela se fait souvent sans modification du code: l'usine méthode est la mise en œuvre nom de la classe par l'intermédiaire d'un paramètre de propriété, et il instancie l'aide de la réflexion, donc, tout ce que vous devez faire pour passer des implémentations, modifier un fichier de propriétés. Il ya effectivement des cadres - comme
spring
ouguice
- ce "l'injection de dépendance" mécanisme pour vous, mais je n'entrerai pas dans les détails, d'abord, parce qu'il est vraiment au-delà de la portée de votre question, et aussi, parce que je ne suis pas forcément convaincu que les avantages que vous obtenez à partir de l'utilisation de ces cadres en vaut la peine intégration avec eux pour la plupart des applications.L'autre (probablement plus de chances d'être pris avantage de) l'avantage de cette "usine approche" par opposition à la statique est la capacité de test. Imaginez que vous écrivez un test unitaire, qui doit tester la logique de votre
App
classe indépendamment de toute DAO sous-jacent. Vous ne voulez pas utiliser tout réel de stockage sous-jacent pour plusieurs raisons (vitesse, d'avoir à mettre en place, et nettoyer par la suite, d'éventuelles collisions avec d'autres tests, possibilité de polluer les résultats de test avec des problèmes dans DAO, rien à voir avecApp
, qui est actuellement mis à l'épreuve, etc.).Pour ce faire, vous voulez un framework de test, comme
Mockito
, qui permet de "se moquer de" la fonctionnalité d'un objet ou d'une méthode, en le remplaçant par un "dummy" de l'objet, avec des comportement (je vais passer les détails, parce que, là encore, au-delà de la portée). Ainsi, vous pouvez créer ce mannequin objet le remplacement de votre DAO, et de faire de laGreatDAOFactory
retourner votre mannequin à la place de la vraie chose en appelantGreatDAOFactory.setDAO(dao)
avant le test (et de les restaurer après). Si vous avez été en utilisant des méthodes statiques au lieu de l'instance de la classe, ce ne serait pas possible.Un autre avantage, qui est un peu similaire à la commutation de bases de données que j'ai décrit ci-dessus est "proxénétisme" votre dao avec des fonctionnalités supplémentaires. Supposons que votre application devient plus lente que la quantité de données dans la base de données augmente, et que vous décidez que vous avez besoin d'un cache couche. Mettre en œuvre une classe wrapper, qui utilise le réel dao instance (fournis comme un constructeur de param) pour accéder à la base de données, et met en cache les objets qu'il lit dans la mémoire, de sorte qu'ils peuvent être rendus plus rapide. Vous pouvez alors faire votre
GreatDAOFactory.getDAO
instancier ce wrapper, pour l'application de profiter de il.(Ce qui est appelé "délégation " modèle" ... et il semble comme une douleur dans le cul, surtout quand vous avez beaucoup de méthodes définies dans votre DAO: vous aurez à mettre en œuvre tous dans l'emballage, même à modifier le comportement d'un seul. Alternativement, vous pouvez simplement sous-classe votre dao, et ajouter la mise en cache de cette façon. Ce serait beaucoup moins ennuyeux codage initial, mais peut devenir problématique lorsque vous décidez de changer la base de données, ou, pire, d'avoir une option de commutation implémentations d'avant en arrière.)
Un tout aussi largement utilisés (mais, à mon avis, inférieur) alternative à la "fabrique" de la méthode est de faire le
dao
une variable de membre dans toutes les classes qui en ont besoin:De cette façon, le code qui instancie ces classes doit instancier l'objet de dao (pourrait toujours utiliser de l'usine), et de l'offrir comme un paramètre du constructeur. L'injection de dépendance cadres je l'ai mentionné ci-dessus, généralement de faire quelque chose de semblable à cela.
Cette offre tous les avantages de la "fabrique" méthode d'approche, que j'ai décrit plus tôt, mais, comme je l'ai dit, n'est pas aussi bon à mon avis. Les inconvénients sont ici d'avoir à écrire un constructeur pour chacune des classes de votre application, en faisant exactement la même chose encore et encore, et également ne pas être en mesure d'instancier les classes facilement en cas de besoin, et certains ont perdu plus de lisibilité: avec une assez grande base de code, d'un lecteur de code, pas familier avec elle, va avoir du mal à comprendre la mise en œuvre de la dao est utilisé, comment il est instancié, si c'est un singleton, un thread-safe mise en œuvre, qu'il garde de l'état, ou caches quelque chose, la façon dont les décisions sur le choix d'une mise en oeuvre particulière sont prises etc.
boolean
pour enregistrer/supprimer des opérations pour indiquer que l'persistent sur le disque/la base de données a été effectuée avec succès.Nah, vous souhaitez lancer une exception si elle ne parvient pas, de toute façon: il vous permet de communiquer beaucoup d'informations précieuses sur l'échec à l'appelant, par rapport à tout simplement retourner false, et permet également la gestion d'erreur sur l'appelant côté moins lourd: au lieu de vérifier l'état de chaque appel et de la propagation de tout le chemin jusqu'à la pile, ils n'auraient qu'à intercepter l'exception d'une fois, au niveau où il doit être manipulé.
C'est une sous-estimé la réponse, bien fait! Une question, pourquoi ne
setDAO
retour de l'ancienne précédent/DAO plutôt que de simplement retourner rien? Comment pourrait-il être utilisé?désolé, juste vu votre question ici 🙂 La raison pour
setDAO
pour revenir à la valeur précédente est de sorte que vous pouvez les restaurer plus tard:DAO oldDao = setDAO(mock); try { doTest(); } finally { setDAO(oldDao); }
vous avez vraiment besoin d'écrire un article complet avec une réelle mise en œuvre qui serait d'une grande aide !
OriginalL'auteur Dima