Un DAO dovrebbe essere singleton o no?

10

Sto sviluppando un'API RESTful e penso che sia conveniente usare DAO per le mie risorse perché, anche se ho intenzione di utilizzare solo la memoria per archiviarle, non voglio chiudere una porta a chiunque usi la mia libreria se ha deciso di utilizzare un'implementazione del database per il DAO.

La mia domanda è se il DAO dovrebbe essere un singleton o no. In caso contrario, il servizio avrà un'istanza del DAO e avrà un aspetto approssimativo come questo:

@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);
    }
}

Sebbene il DAO fosse un singleton, ma immagino che non ci sarebbe molta differenza, solo nella prima riga:

private IEventSchedulerDao dao = EventSchedulerDao.getInstance();

Dovrei comunque usare un'istanza di IEventSchedulerDao , ma immagino che tutti i singleton funzionino correttamente? Per qualche ragione collego sempre i singleton ai metodi statici, quindi invece di avere un'istanza singleton visibile all'utente con getInstance() , questo sarebbe nascosto e lui / lei userebbe solo EventSchedulerDao.get(name) , ecc ... in modo statico . È una cosa o sono solo io?

Quindi, dovrei o non dovrei avere DAO singleton?

E come una domanda a parte, va bene il mio approccio per avere delle porte aperte affinché l'utente possa implementare i propri DAO?

    
posta dabadaba 03.06.2016 - 12:52
fonte

3 risposte

11

Non userei un singleton. È un anti-pattern riconosciuto e rende difficile il test. Preferirei molto iniettare in un'implementazione concreta e fare in modo che il servizio faccia riferimento a un'interfaccia DAO (che consente di inserire diverse implementazioni in )

    
risposta data 03.06.2016 - 12:58
fonte
2

Un D ata un ccess O bject dovrebbe esistere solo una volta nella tua applicazione. La logica rimane la stessa, le uniche cose che sono diverse sono i valori che entrano ed escono dai metodi forniti dal DAO.

Con questo in mente, ovviamente la prima cosa che succede di solito è implementare il DAO come un strong singleton , cioè quando hai un metodo static su una classe factory, qualcosa come getInstance , lazy che carica un'istanza del DAO se è null e lo restituisce.

Scusami se la sintassi non è completamente corretta, non sono un programmatore 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();
    }
}

È incredibilmente difficile da testare, perché non è possibile sostituire l'implementazione senza alterare il codice della classe UsesDao . Questo può essere fatto attraverso alcune patch per scimmia , ma generalmente non è considerato una buona pratica.

Poi c'è il modo migliore, il pattern debole singleton , in cui non recuperi un'istanza attraverso un metodo static , ma fai in modo che tutte le classi dipendano dall'istanza tramite un costruttore o un setter (nel tuo EventSchedulerService stai usando l'iniezione setter).

L'unico problema è che devi assicurarti che tutte le classi, che dipendono da un'istanza di classe che dovrebbe esistere solo dopo il ciclo di vita dell'applicazione, stiano prendendo la stessa istanza del loro parametro, ad es. new viene chiamato una sola volta sull'oggetto DAO nell'intera applicazione.

Ovviamente, questo è incredibilmente difficile da tracciare e la costruzione del grafo degli oggetti è un lavoro noioso e noioso.

Fortunatamente, ci sono IoC contenitori, che lo rendono molto più facile. Oltre a Spring , il Guice Il contenitore IoC di Google è molto popolare tra i programmatori Java.

Quando si utilizza un contenitore IoC, lo si configura per comportarsi in un certo modo, ad es. puoi dire se è come costruire determinate classi e se qualche classe è richiesta come dipendenza, come dovrebbe essere la dipendenza (se dovrebbe sempre essere una nuova istanza o un singleton) e il contenitore lo collega tutto.

Puoi controllare questo link per un esempio singleton con Guice.

Pro e contro dell'uso di un contenitore IoC

Pro

  • risparmiando budget non dovendo scrivere tutti i metodi di produzione da soli
  • (di solito) configurazione molto semplice
  • sviluppo rapido

Contro

  • la magia di un mago, le classi sono in qualche modo costruite e non puoi davvero vedere come è successo
  • un piccolo calo delle prestazioni dovuto alla ricerca della classe (le factory scritte manualmente saranno leggermente più veloci)
risposta data 05.06.2016 - 15:24
fonte
1

Singleton si riferisce al concetto solo una istanza e al modo di accedere all'istanza (tramite il famoso metodo statico getInstance () )

Ma c'è ancora un'istanza dietro tutto questo. Un oggetto creato con una sorta di accesso restretto.

Nel tuo caso, preferirei optare per l'approccio DI (iniezione di dipendenza). Come il primo blocco di codice che hai esposto. Solo un piccolo cambiamento. Iniettare il DAO tramite il costruttore. Per rimuovere o meno il setter dipende da te. Se si desidera proteggere Controller da modifiche in runtime, rimuoverlo. Se vuoi offrire questa possibilità, mantienila.

Hai ragione nell'usare un'interfaccia e offrire una finestra aperta per ulteriori implementazioni di DAO. Può o non può essere necessario. Ci vuole solo un minuto in più di lavoro, ma rende il tuo design flessibile. Il tuo in memoria DAO è abbastanza comune. Molto utile come mock in fase di test. O come implementazione DAO predefinita.

Solo un suggerimento. Le risorse statiche (oggetti, metodi, costanti o variabili) sono come risorse globali. Se i globali sono malvagi o no è questione di bisogni o gusti. Tuttavia ci sono implicite carenze legate a loro. Questi sono relativi a concorrenza , thread-safety (in Java, non so su altri linguaggi), serializzazione ...

Quindi suggerirei di usare la statica con cautela

    
risposta data 04.06.2016 - 12:11
fonte

Leggi altre domande sui tag