È considerata una cattiva pratica effettuare una chiamata DAO nel costruttore di un oggetto?

6

Sto cercando di capire il miglior design per istanziare un oggetto che richiede due chiamate separate al livello dati attraverso un DAO. L'oggetto non è utilizzabile fino a quando queste chiamate non sono state fatte (perché richiede i dati recuperati dal database). Ho trovato tre soluzioni possibili:

  1. Creare un metodo nello stesso DAO che ottiene i dati necessari dal database e quindi passa i dati al costruttore dell'oggetto. L'oggetto viene restituito come valore di ritorno.
  2. Crea un metodo nella classe che sta usando l'oggetto. Questo metodo effettua entrambe le chiamate a metodi pubblici nel DAO, quindi crea un'istanza e restituisce l'oggetto come nel passaggio 1.
  3. Passa il DAO come parametro al costruttore dell'oggetto. Il costruttore quindi effettuerà entrambe le chiamate necessarie al DAO, impostando le proprie variabili membro senza la necessità di setter. Il DAO non viene utilizzato diverso dal costruttore.

Esempi, se SomeObject è l'oggetto che voglio creare, e Foo è la classe che ne farà uso:

1 - DAO Contiene la logica:

public SomeObject getSomeObject(){ // this DAO method called by Foo class
     data1 = getData1();
     data2 = getData2();
     return new SomeObject(data1,data2);
}

2 - La classe che usa l'oggetto contiene la logica:

public class Foo {
    ...
         public void useSomeObject() {
              SomeObject obj = createSomeObject();
              obj.doStuff();
         }

         private SomeObject createSomeObject() {
              data1 = dao.getData1();
              data2 = dao.getData2();
              SomeObject someObject = new SomeObject(data1,data2);
              return someObject;
         } 
}

3 - SomeObject prende DAO come parametro e lo utilizza nel costruttore:

public class SomeObject {
...
      public SomeObject(DAO dao) {
           data1 = dao.getData1();
           data2 = dao.getData2();
      }
...
 }

Spero che questi esempi siano sufficienti per esprimere il mio punto. Qualcuna di queste soluzioni ha un design migliore rispetto alle altre? In caso contrario, quale soluzione è considerata la migliore pratica?

Grazie.

    
posta Wallace Brown 06.08.2014 - 22:23
fonte

3 risposte

4

Nel classico OOP, la nozione di incapsulamento incarna l'idea di combinare i dati con il codice; cioè, fornendo metodi che agiscono specificamente sui dati che rappresentano. Ad esempio, un oggetto Cliente contiene solo quei metodi che riguardano specificamente il "comportamento" del cliente.

Gli oggetti persistenti sono una preoccupazione ortogonale.

L'oggetto Cliente non dovrebbe sapere nulla su come viene salvato o recuperato da un database, file XML o altro (il concetto è chiamato Persistenza Ignoranza ). Questo è il motivo per cui l'approccio preferito, specialmente in un sistema di grandi dimensioni, consiste nell'utilizzare un meccanismo di persistenza generalizzato come un Object Relational Mapper per archiviare e recuperare oggetti, e quindi estrarre tale funzionalità attraverso metodi Repository che restituiscono oggetti o eseguono azioni di business su i dati.

Questo ti solleva dalla responsabilità di dover codificare un'implementazione di persistenza per ogni classe che crei.

Ulteriori letture
L'unità del modello di lavoro e persistenza ignoranza

    
risposta data 06.08.2014 - 22:50
fonte
3

Il tuo approccio nell'esempio 1, fai in modo che DAO chiami il costruttore, e si avvicini molto al Pattern del repository.

Tuttavia, ha più senso avere un repository effettivo per coordinare.

class SomeObjectRepository {
  SomeObjectDAO sod;
  ...
  SomeObject getSomeObject() {
    return new SomeObject(sod.getData1(), sod.getData2());
  }
}

Il DAO viene associato al repository (un singleton) quando viene creato. Foo quindi chiama il metodo repository per ottenere l'oggetto.

In questo modo, l'oggetto viene disaccoppiato dal DAO, il DAO esegue solo le operazioni di base e sono più facilmente testati l'uno rispetto all'altro.

    
risposta data 06.08.2014 - 22:46
fonte
2

Vorrei andare con la tua terza opzione. Ti permette di passare qualunque DAO vuoi, e questo potrebbe essere molto utile per i test. Rende anche il tuo codice un po 'più flessibile: nel caso in cui i dettagli del recupero dei dati cambino, hai solo modificato la classe DAO e SomeObject dovrebbe funzionare più o meno lo stesso.

La prima opzione non è così male. I metodi di recupero dei dati sono compresi in SomeObject , quindi ora la tua classe è un oggetto business e un DAO.

La seconda opzione potrebbe portare a una situazione in cui createSomeObject viene copiata e incollata, poiché la necessità di creare una SomeObject aumenta e si diffonde nell'intera applicazione (lo so, potrebbe non succedere, ma potrebbe). E quando ciò accade, ti piacerebbe che il codice di recupero dei dati fosse posizionato in un punto centrale, come ad esempio il costruttore per SomeObject , che è dove hai iniziato.

    
risposta data 06.08.2014 - 22:30
fonte

Leggi altre domande sui tag