2012-07-27 22 views
11

Ho cercato molte informazioni sul modello DAO e ho capito il motivo. Ma mi sembra che la maggior parte delle spiegazioni non stiano raccontando l'intera storia e con ciò intendo dove useresti il ​​tuo DAO. Così per esempio se ho una classe utente e un'UserDAO corrispondente che è in grado di salvare e ripristinare gli utenti per me, che è il modo corretto:Modello DAO e oggetti modello

  • Il controller crea l'oggetto utente e lo passa al UserDAO a salvarlo al database

  • il controller crea l'oggetto utente e nel suo costruttore dell'oggetto utente effettua una chiamata al userDAO al fine di salvare se stesso nel database

  • si tratta di un odore di codice e si è manca una classe extra "UserManager" che il controllore chiederà di creare all'utente. L'UserManager è responsabile della creazione l'utente e chiedendo al UserDAO per salvarlo

Mi sento come la terza opzione è la migliore, perché tutto ciò che il controller è responsabile è delegare la richiesta per l'oggetto del modello corretto . Qual è il tuo modo preferito? Mi sto perdendo qualcosa qui?

risposta

12

Dalla mia esperienza con i DAO, il primo approccio è l'unico corretto. Il motivo è che ha le responsabilità più chiare e produce il minimo ingombro (beh, alcuni programmatori rispettabili considerano gli stessi DAO come un disordine. Adam Bien vede il modello DAO originale già implementato nello EntityManager e altri DAO per la maggior parte inutili "pipe")

Approccio 2 associa il modello al DAO, creando una "dipendenza upstream". Quello che intendo è che di solito i modelli sono distribuiti come pacchetti separati e sono (e dovrebbero essere) ignoranti dei dettagli della loro persistenza. Un modello simile a quello che stai descrivendo è lo Active Record pattern. È ampiamente utilizzato in Ruby on Rails ma non è stato implementato con la stessa eleganza e semplicità in Java.

Approccio 3 - che cosa dovrebbe essere il punto dello UserManager? Nell'esempio, il Manager esegue 2 attività: ha i compiti di una fabbrica Utente ed è un proxy per le richieste di persistenza. Se si tratta di una fabbrica e ne hai bisogno, è necessario denominarla UserFactory senza imporre ulteriori attività su di essa. Per quanto riguarda il proxy, perché dovresti averne bisogno?

IMHO molte classi denominate ...Manager hanno un odore. Il nome stesso suggerisce che la classe non ha uno scopo chiaro. Ogni volta che ho voglia di nominare una classe ...Manager, è un segnale per me trovare un nome più appropriato o riflettere seriamente sulla mia architettura.

+1

Solo per aggiungere a questo; Generalmente creo anche un oggetto UserServices responsabile della gestione della sessione/transazione. Quindi ho il UserDAO che è responsabile solo per fare effettivamente le query invocate da UserServices. – sbrattla

+0

@sbrattla - Se si utilizzano transazioni utente, questo può sicuramente avere senso. Assumevo automaticamente transazioni EJB, sebbene OP non le menzionasse. Kneejerk :) – kostja

+0

@ Tom se non siete d'accordo - per favore elaborate – kostja

0

L'oggetto di accesso ai dati (DAO) deve essere utilizzato più vicino al livello di accesso ai dati dell'applicazione. L'oggetto di accesso ai dati esegue effettivamente le attività di accesso ai dati.Quindi fa parte del livello di accesso ai dati.

I livelli di architettura precedenti a DAO potrebbero variare nei progetti.

I controllori servono fondamentalmente per controllare il flusso di richiesta. Quindi sono quasi vicini all'interfaccia utente. Anche se Manager, Handler è una cattiva idea, possiamo ancora aggiungere uno strato tra controller e DAO. Quindi il controllore pre-processerà i dati provenienti da una richiesta o uscenti (integrità dei dati, sicurezza, localizzazione, i18n, trasformazione in JSON, ecc.). Invia dati al servizio sotto forma di oggetti di dominio (Utente in questo caso). Il servizio invocherà alcune logiche di business su questo utente o lo utilizzerà per alcune logiche di business. E poi lo passerebbe a DAO.

Avere la logica di business nello strato di controllo non è buono se si stanno sostenendo più client come JSP, WebServices, dispositivi palmari, ecc

0

Supponendo controller significa che la "C" in MVC, la vostra terza opzione è il diritto approccio. Generalmente parlando, il codice del controller estende o segue le convenzioni di un framework. Uno degli ideali di MVC è lo scambio di framework, che è in realtà il Controller, dovrebbe essere relativamente facile. I controller dovrebbero semplicemente spostare i dati avanti e indietro tra il modello e i livelli di visualizzazione.

Dal punto di vista del modello, i controllori devono interagire con uno service layer - a contextual boundary - nella parte anteriore dello domain model. L'oggetto UserManager sarebbe un esempio di un pezzo che considereresti parte del tuo livello di servizio, ovvero l'API pubblica del modello di dominio.

0

Per il primo approccio; IMHO, il controller che chiama un metodo su un oggetto DAO non è un buon progetto. I controllori devono chiedere agli oggetti di livello "servizio" sul business. Come questi "servizi" persistono i dati non sono una preoccupazione per il controller.

Per il secondo approccio; a volte potresti voler semplicemente creare l'oggetto, quindi il dovere del costruttore e il dovere persistente non devono essere strettamente accoppiati come questo.

Infine, il gestore o gli oggetti di servizio è una buona astrazione per l'architettura a più livelli. In questo modo è possibile raggruppare i flussi aziendali nelle classi e nei metodi appropriati.

Ma per Play, gli oggetti companion di case class sono anche un buon candidato da utilizzare come DAO. La natura singleton di questi oggetti lo rende un buon candidato.

case class TicketResponse(appId: String, ticket: String, ts: String) 

object TicketResponse{ 
    implicit val ticketWrites = Json.writes[TicketResponse] 

    def save(response: TicketResponse) = { 

    val result = DB.withConnection { 
     implicit connection => 

     SQL("insert into tickets(ticket, appid, ts)" 
      + " values ({ticket},{appid},{ts})") 
      .on('ticket -> response.ticket, 'appid -> response.appId, 'ts -> response.ts).executeInsert() 
    } 

    } 

}