Una classe DTO che ha un ArrayList di tipo proprio - è considerato un buon progetto?

4

Mi sono imbattuto in una classe DTO come quella in basso.

class PersonDTO {
   private String firstName;
   private String middleName;
   private String lastName;
   private String dob;

   // some 50 fields more
   private List<PersonDTO> persons;

   //getters and setter
}

Domanda 1: è una buona pratica avere classi DTO così grandi con così tante proprietà?

Domanda 2: è una buona pratica avere una classe DTO con un ArrayList del suo tipo? Non causerebbe un riferimento circolare?

Aggiornamento:

Lavoro per un prodotto nel settore sanitario. Il caso d'uso è di generare un rapporto di tutti gli utenti nel sistema. Insieme alla lista degli utenti, il report deve anche mostrare le informazioni di riepilogo. I dati devono essere serializzati, perché l'interfaccia utente è in attesa di una risposta JSON.

Di seguito è l'effettivo DTO che stavo prendendo circa.

Un metodo è stato scritto nella classe DAO, che restituisce un oggetto UserDTO. Questo oggetto UserDTO che viene restituito .. consiste in un elenco di tutti gli utenti e alcune informazioni di riepilogo come: medici totali, infermieri totali ecc.

class UserDTO{
    private String userID; //This is unique

    private String firstName;
    private String middleName;
    private String lastName;
    private String dob;

    private String userType; // value can be DT(for doctor), ST(for nurse), 

    private int totalDoctorCount; //Holds the total number of UserDTOs with userType value set to DT in the ArrayList of users.

    private int totalNurseCount; //Holds the total number of UserDTOs with userType value set to ST in the ArrayList of users.


    // there are some 40 more properties.

    private List<UserDTO> users;

        //In this class there are also properties like below... 

        private String primaryAddrStreetName;
        private String primaryAddrCity;
        private String primaryAddrState;
        private String primaryAddrCountry;
        private String primaryAddrZipcode;

        private String billingAddrStreetName;
        private String billingAddrCity;
        private String billingAddrState;
        private String billingAddrCountry;
        private String billingAddrZipcode;

        private String shippingAddrStreetName;
        private String shippingAddrCity;
        private String shippingAddrState;
        private String shippingAddrCountry;
        private String shippingAddrZipcode;
}

Domanda 3: questo design DTO è adatto a questo caso d'uso? se no, allora cosa suggeriresti?

Domanda 4: l'utente ha più indirizzi. Ma, i dettagli dell'indirizzo non dovrebbero essere nella sua classe (qualcosa come UserAddressDTO) e quindi dovremmo aggiungere un array / ArrayList di UserAddressDTO in UserDTO ??

Domanda 5: Si prega inoltre di fornire alcune informazioni su come questo tipo di DTO possa influenzare la memoria JVM. Il rapporto recupera migliaia di record.

    
posta madan 10.06.2017 - 11:24
fonte

4 risposte

4

Domanda 1: enorme DTO

L'obiettivo di un DTO è di trasferire dati tra processi o livelli in modo da ridurre il numero di chiamate al metodo.

Non è quindi scioccante avere un enorme elenco di campi in una tale struttura. L'alternativa è implementare il DTO con una struttura più complessa, come ad esempio un ResultSet (o un set di dati in un contesto non jaa), che raggruppa entità diverse in un unico oggetto. L'inconveniente è quindi che la costruzione di tale oggetto e l'accesso ai suoi elementi richiede più tempo, che con la vostra struttura piatta (e brutta, ma efficiente).

FYI, qui troverai alcuni vantaggi e responsabilità del DTO.

Domanda 2 (aggiornata dopo la modifica) **

Avere un elenco di PersonDTO in PersonDTO significa che il DTO ha una struttura ricorsiva (ad es. come un albero). Quindi non sono solo dati piatti di un Person , ma in effetti un Person e un gruppo di Persons correlato. La struttura dei dati è ricorsiva.

Questo non implica un riferimento circolare, ma hai ragione, è necessaria una certa attenzione. Tutto dipende dalla struttura dei dati originale:

  1. Se gli oggetti originali formano una gerarchia (ad esempio, un manager e i suoi dipendenti, alcuni di loro stessi hanno i propri dipendenti), non c'è alcun problema a creare il DTO. Lo stesso se è un'altra forma di grafico aciclico.
  2. Se gli oggetti originali formano un grafico con cicli possibili (ad esempio, una persona e i suoi amici), c'è il rischio di pedalare per sempre quando si costruisce il DTO. È possibile utilizzare un rilevamento del ciclo per impedire di trasferire più volte lo stesso oggetto. Tuttavia, fare ciò significherebbe perdere alcune relazioni nel trasferimento. In questo caso questo DTO sarebbe un cattivo progetto.

Si noti inoltre che una stessa persona potrebbe apparire più volte nel DTO, in elenchi diversi (ad esempio un dipendente part-time che lavora per due reparti). Sfortunatamente, durante il trasferimento dei dati, se gli oggetti vengono deserializzati per essere trasferiti sulla rete e poi serializzati di nuovo, l'identità dell'oggetto (che hai in java con lo stesso riferimento) potrebbe andare persa e ti ritroverai con due diversi oggetti che replicano gli stessi dati. Dal lato della reception, quindi, dovresti anche fare un po 'di attenzione: devi decidere se rilevi un'identità di questo tipo o se ritieni che tutte le persone saranno sempre diverse.

Conclusione: questa struttura potrebbe essere ok, ma richiede alcune informazioni sugli oggetti del dominio originale da confermare.

Alternativa: Una struttura DTO molto più sicura sarebbe quella di dare a ogni persona un ID e organizzare il DTO come una raccolta di persone con il loro id. L'elenco di PersonDTO potrebbe quindi essere sostituito con un elenco di id. Questo è molto più flessibile, perché funzionerebbe per tutti i tipi di grafici delle persone e senza bisogno di alcun rilevamento di identità.

Domanda 3 e ultima modifica

Se l'obiettivo di questa struttura DTO è solo quello di fornire un elenco di utenti non collegati , dovrebbe avere la struttura:

class UserDTO {             // Only properties of a single user
    private String userID; 
    private String firstName;
    ...
    private String userType;  
};
class UserListDTO {         // Only properties of the list as a whole
    private int totalDoctorCount; 
    ...
    private List<UserDTO> users;
};

Come vedi, un design DTO corretto è spesso correlato a una moltiplicazione di classi DTO. Questo è un argomento ben noto in quanto è possibile verificare negli svantaggi esposti in questo articolo qui .

Gonfiare un DTO unico per combinare i due livelli in una singola classe è una scorciatoia che non rispetta il principio di responsabilità singola . È anche ambiguo: l'utente principale dovrebbe essere aggiunto al gruppo o no? Ha poi contato nelle statistiche? Gli utenti nella lista hanno sempre una lista vuota? Devono fornire statistiche su se stessi? Cosa succede se un utente nell'elenco viene fornito con utenti inattesi nella sua lista? Tutte queste domande e l'elaborazione extra, solo per evitare una classe aggiuntiva ...

In questo caso, è un cattivo design.

    
risposta data 10.06.2017 - 14:21
fonte
1

Question 1: Is it a good practice to have such huge DTO classes with so many properties?

Come altri hanno già menzionato, un DTO può certamente essere così grande se il suo consumatore ne ha bisogno. È difficile commentare se un DTO così ampio è una buona pratica perché DTO ha uno scopo così ristretto che non c'è una reale variazione di "buona pratica" nell'usarli.

Question 2: Is it a good practice to have a DTO class having an ArrayList of its own type? Wouldn't it cause a circular reference?

In termini di Modellazione , una Person non è composta da più%% di altri% co_de. Un Persons potrebbe avere più Person di tipo siblings . Il punto essendo un membro chiamato Person non trasmette alcuna informazione rilevante sulla sua relazione con l'oggetto. D'altra parte, è ovvio che un membro chiamato persons descrive una relazione familiare tra queste istanze di siblings .

    
risposta data 11.06.2017 - 02:38
fonte
1

Wikipedia

data transfer object (DTO) is an object that carries data between processes. The motivation for its use is that communication between processes is usually done resorting to remote interfaces (e.g. web services), where each call is an expensive operation. Because the majority of the cost of each call is related to the round-trip time between the client and the server, one way of reducing the number of calls is to use an object (the DTO) that aggregates the data that would have been transferred by the several calls, but that is served by one call only

Secondo la definizione di cui sopra, se il DTO è indirizzato a ridurre il numero di chiamate tra processi, potremmo discutere delle dimensioni del DTO ma non della sua adeguatezza. D'altra parte, se il DTO non risponde a nessuna strategia di comunicazione, la risposta probabile è per favore, riesamina il tuo progetto . Chiunque consumerà il DTO avrà difficoltà a esplorare, analizzare ed estrarre i dati da tale mostruosità.

Per quanto riguarda la seconda domanda, potrebbe esserci un riferimento circolare se per qualche ragione lo stesso DTO viene fatto riferimento da qualche parte nella Lista o referenziato da una qualsiasi delle liste interne del DTO. E così via.

Aggiornato dopo la modifica

@Christophe ha già detto ciò che pensiamo tutti (più o meno). se UserDTO porta con sé tutti i dati richiesti per il report, lo hai fornito con troppe responsabilità.

Considera le prossime 2 opzioni:

  • che modella la risorsa web ReportDTO composta da altri DTO e i suoi attributi locali.

  • facendo più chiamate al server. Sappiamo che l'obiettivo del DTO è l'opposto di questo, ma non impazzire, ridurre le 50 chiamate a 1 è eccellente, ma non farlo a rischio di implementare l'One DTO ( un DTO a portali tutti, e nelle tenebre li leghi ). Riducendo il numero di chiamate da 50 a 5 è ancora un grosso miglioramento.

risposta data 10.06.2017 - 14:35
fonte
0

Cinquanta proprietà sembrano un po 'eccessive. Dovresti cercare di tenerli il più ordinati possibile. Includere solo ciò di cui hai bisogno. Anche se ho visto alcuni che sono 10-15 proprietà.

E per quanto riguarda il ArrayList , puoi averne uno senza problemi. Il riferimento circolare si verificherebbe solo se per qualche ragione memorassi l'oggetto reale che sta facendo il lavoro come riferimento o qualcosa di strano in quel modo.

    
risposta data 10.06.2017 - 11:41
fonte