Usa POJO o Map quando c'è un numero finito di chiavi conosciute?

3

Ho alcuni set di dati con coppie di valori-chiave, ma c'è solo un insieme limitato e conosciuto di chiavi, tutte le chiavi dovrebbero sempre essere presenti su quei dati e hanno tutti lo stesso tipo per il valore. Ha più senso usare un enum per la chiave in una mappa (come Map<SomeEnum, String> ) o creare una nuova classe per rappresentarlo? Entrambi gli approcci possono funzionare, ma mi chiedo quale sia più sensato.

Se questi dati fossero in JSON, potrebbero avere un aspetto simile a questo.

{
  "alpha": "blah",
  "bravo": "blah blah",
  "charlie": "blah blah blah"
}

Il mio istinto è che l'approccio di classe è migliore. Il mio ragionamento è che usare Map è più per quando si hanno chiavi o chiavi arbitrarie che saranno sconosciute in fase di compilazione. Uno dei vantaggi di una classe con getter è che tutte le chiavi possibili sono proprio lì, sono essenzialmente metodi. Rende il codice più "auto documentante" in un certo senso. L'unico vero svantaggio di questo approccio è che c'è più spazio per scrivere (che può essere alleviato con cose come gli strumenti di generazione di sorgenti IDE).

Il codice per l'approccio di classe sarebbe qualcosa di simile.

class Data {
  private final String alpha;
  private final String bravo;
  private final String charlie;
  // Constructor and getters omitted for brevity
}

Il codice per l'approccio della mappa sarebbe simile a questo.

enum Key {
  ALPHA, BRAVO, CHARLIE
}
//...
Map<Key, String> data;
    
posta Captain Man 26.07.2018 - 22:22
fonte

5 risposte

3

Vorrei andare con l'approccio pojo (oggetto).

Entrambi sono abbastanza ragionevoli. Ma quando si guarda all'utilizzo l'approccio ad oggetti è più chiaro e chiaro.

E, soprattutto, generalizza meglio. Considera se il valore associato a uno dei nomi non fosse una stringa?

E se fosse un numero intero o un array o un'altra enumerazione? Potrebbe anche essere un'altra struttura (POJO).

risposta data 26.07.2018 - 23:01
fonte
2

Dipende dai modelli di utilizzo.

Preferirei generalmente la versione POJO perché è più pulita, più sicura e più facile per l'ottimizzatore di HotSpot.

Ma mi vengono in mente due situazioni in cui passare alla versione della mappa:

  • Se le istanze tipiche riempiono solo una piccola parte dei campi, la soluzione Map può essere più efficiente in termini di memoria. Ma in questo momento è l'ottimizzazione prematura, quindi non dovrebbe essere fatto inizialmente, solo dopo aver trovato un problema di consumo di memoria, profilazione e identificazione della classe come origine della fame di memoria.

  • Se hai bisogno di getter e setter generici con la chiave desiderata come parametro, una mappa lo supporta in modo del tutto naturale, mentre il POJO ha bisogno di una riflessione o di una lunga istruzione switch.

risposta data 28.07.2018 - 00:32
fonte
1

Perché non usare entrambi?

Puoi creare un oggetto che contiene la chiave identificata con precisione ( alpha , bravo e charlie nel tuo caso).

Quindi includi una mappa che conterrà tutti i campi extra.

Usando Jackson puoi farlo facilmente.

Sarebbe come questo:

public class Data {
    private final String alpha;
    private final String beta;
    private final String charlie;

    private final Map<String, Object> extraFields;

    // constructor, getters and setters

    @JsonAnyGetter
    public Map<String, Object> getExtraFields(){
           return extraFields;
    }

    @JsonAnySetter
    public void setExtraField(String key, Object value) {
           extraFields.put(key, value);
    }

}

Se devi davvero scegliere tra l'approccio della mappa e il POJO, sicuramente sceglierei POJO.

Sarai in grado di avere una struttura più complessa ( delta potrebbe essere un oggetto di tipo SubData ). Questa struttura sarà quindi strongmente digitata e non dovrai affrontare più cast. In questo modo, si riducono le possibilità di errore di runtime e si migliora la leggibilità del codice.

    
risposta data 27.07.2018 - 11:57
fonte
0

Usa un POJO. Per la serializzazione è possibile utilizzare diversi DTO che il mappatore mapperà in modo appropriato.

Il vantaggio è che puoi questo DTO ~

class DataView1DTO {
  private alpha;
  // getters / setters
}

class DataView2DTO {
  private alpha;
  private charlie;
  // getters / setters
}

È quindi possibile utilizzare ObjectMapper per trasformare un oggetto "Dati" in DataView1DTO o DataView2DTO proprio come questo

Data myData // ...
DataView1DTO dto = myModelMapper.writeValue(myData, DataView1DTO.class);
// or...
DataView2DTO dto = myModelMapper.writeValue(myData, DataView2DTO.class)

e quindi convertirlo in JSON come questo

String dtoJson = myObjectMapper.writeValueAsString(dto);

Un esempio più appropriato sarebbe dati dell'utente come password o altri dati sensibili che non è possibile trasferire. Oppure potrebbe dipendere dai privilegi del destinatario, quindi avresti bisogno di diversi tipi di "viste".

Spero che tu capisca cosa intendo.

    
risposta data 26.07.2018 - 23:16
fonte
0

L'approccio (c) più snello e rapido sarebbe una lista o array piuttosto che una mappa / dizionario. L'enum potrebbe essere solo un indice se lo definisci con valori di incremento fissi.

Per evitare il cast ogni volta potresti incapsulare la lista / matrice in una classe che offre getter e setter validi e sicuri per i tuoi elementi. Questo approccio ti permetterebbe anche di leggere i tuoi dati da un file.

    
risposta data 26.07.2018 - 23:23
fonte

Leggi altre domande sui tag