Je suis en train de développer une API RESTful et je pense qu'il est pratique d'utiliser des DAO pour mes ressources, car même si je prévois d'utiliser uniquement de la mémoire pour les stocker, je ne veux pas fermer la porte à quiconque utilise ma bibliothèque s'il décide d'utiliser une implémentation de base de données pour le DAO.
Ma question est de savoir si le DAO doit être un singleton ou non. Si ce n'est pas le cas, le service aura une instance du DAO et il ressemblerait à peu près à ceci:
@Path("eventscheduler")
public class EventSchedulerService {
private IEventSchedulerDao dao = new EventSchedulerDao();
// in case a different implementation is to be used
public void setEventSchedulerDao(IEventSchedulerDao dao) {
this.dao = dao;
}
@Path("{uniqueName}")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Tournament getTournament(@PathParam("name") String uniqueName) {
return dao.get(uniqueName);
}
@Path("create")
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Tournament createTournament(Tournament tournament) {
return dao.create(tournament);
}
}
Alors que si le DAO était un singleton, mais je suppose qu'il n'y aurait pas beaucoup de différence, juste dans la première ligne:
private IEventSchedulerDao dao = EventSchedulerDao.getInstance();
Je devrais encore utiliser une instance IEventSchedulerDao
, mais je suppose que tous les singletons fonctionnent comme ça, non? Pour une raison quelconque, je corrèle toujours les singletons avec des méthodes statiques, donc au lieu d'avoir une instance de singleton visible par l'utilisateur avec getInstance()
, cela serait masqué et il/elle utiliserait simplement EventSchedulerDao.get(name)
, etc ... d'une manière statique. Est-ce une chose ou est-ce juste moi?
Alors, dois-je ou ne dois-je pas avoir des DAO singleton?
Et comme question secondaire, est-ce que mon approche est d'avoir des portes ouvertes pour que l'utilisateur puisse implémenter ses propres DAO?
Je n'utiliserais pas de singleton. C'est un anti-pattern reconnu , et rend les tests difficiles. Je préfère de beaucoup injecter dans une implémentation concrète, et demander à votre service de référencer une interface DAO (vous permettant d'injecter différentes implémentations dans)
A [~ # ~] d [~ # ~] ata [~ # ~] a [~ # ~ ] ccess [~ # ~] o [~ # ~] bject ne devrait vraiment exister qu'une seule fois dans votre application. La logique reste la même, les seules choses qui sont différentes sont les valeurs entrant et sortant des méthodes fournies par le DAO.
Dans cet esprit, la première chose qui se produit est évidemment d'implémenter le DAO en tant que singleton fort , c'est-à-dire lorsque vous avez un static
méthode sur une classe d'usine, quelque chose comme getInstance
, paresseux chargeant une instance du DAO si elle est nulle et la retournant.
Excusez-moi si la syntaxe n'est pas complètement correcte, je ne suis pas un programmeur Java.
class DaoSingletonFactory
{
private static Dao dao = null;
public static Dao getInstance()
{
if (DaoSingletonFactory.dao == null) {
DaoSingletonFactory.dao = new Dao();
}
return DaoSingletonFactory.dao;
}
}
class UsesDao
{
public void someMethod()
{
Dao dao = DaoSingletonFactory.getInstance();
}
}
C'est incroyablement difficile à tester, car vous ne pouvez pas échanger l'implémentation sans modifier le code de la classe UsesDao
. Cela peut être fait via certains patch de singe , mais n'est généralement pas considéré comme une bonne pratique.
Ensuite, il y a la meilleure façon, le modèle singleton faible , où vous ne récupérez pas une instance via une méthode static
, mais faites toutes les classes dépendent de l'instance via un constructeur ou un setter (dans votre EventSchedulerService
vous utilisez l'injection de setter).
Le seul problème est que vous devez alors vous assurer que toutes les classes, qui dépendent d'une instance de classe qui ne devrait exister qu'une fois le cycle de vie de votre application, prennent la même instance que leur paramètre, c'est-à-dire. new
n'est appelé qu'une seule fois sur l'objet DAO dans toute l'application.
De toute évidence, cela est incroyablement difficile à suivre et la construction du graphique d'objet est un travail fastidieux et ennuyeux.
Heureusement, il existe IoC conteneurs, ce qui le rend beaucoup plus facile. Outre Spring , le Guice conteneur IoC de Google est très populaire parmi les programmeurs Java.
Lorsque vous utilisez un conteneur IoC, vous le configurez pour se comporter d'une certaine manière, c'est-à-dire. vous dites si la façon dont elle est censée construire certaines classes et si une classe est requise en tant que dépendance, à quoi devrait ressembler la dépendance (que ce soit toujours une nouvelle instance ou un singleton) et le conteneur le relie.
Vous pouvez vérifier ce lien pour un exemple singleton avec Guice.
Avantages
Contre
Singleton fait référence au concept juste une seule instance et la façon d'accéder à l'instance (à travers le fameux statique méthode getInstance () )
Mais il y a toujours un exemple derrière tout cela. Un objet construit avec une sorte d'accès restreint.
Dans votre cas, je préférerais une approche DI (injection de dépendance). Comme le premier bloc de code que vous avez exposé. Juste un petit changement. Injectez le DAO via le constructeur. C'est à vous de retirer ou non le passeur. Si vous souhaitez protéger le contrôleur des modifications de l'exécution, supprimez-le. Si vous souhaitez offrir une telle possibilité, gardez-la.
Vous avez raison d'utiliser une interface et d'offrir une fenêtre ouverte pour d'autres implémentations de DAO. Peut ou peut ne pas être nécessaire. Cela ne prend qu'une minute de plus, mais cela rend votre conception flexible. Votre en mémoire DAO est assez courant. Très utile comme maquette au moment du test. Ou comme implémentation DAO par défaut.
Juste un indice. Les ressources statiques (objets, méthodes, constantes ou variables) sont comme des ressources globales. Si les globaux sont mauvais ou non, c'est une question de besoins ou de goûts. Cependant, il y a des lacunes implicites qui leur sont liées. Ceux-ci sont liés à concurrence simultanée , sécurité des threads (en Java, don connais pas les autres langues), sérialisation ...
Je suggère donc d'utiliser la statique avec prudence