Miglior approccio a una struttura dati definita

1

Ho un semplice file di testo con alcuni dati che non posso cambiare, quindi devo creare una struttura dati da utilizzare nella lettura del file e con quella struttura fare alcune migliaia di interazioni.

Il file segue uno schema definito come questo:

AAAAAA:zz_something sometxt1 sometxt2
AAAAAA:zz_something sometxt1 sometxt2
AAAAAA:zz_someotherthing sometxt1 sometxt2
BBBBBB:zz_something sometxt1 sometxt2
BBBBBB:zz_someotherthing sometxt1 sometxt2
BBBBBB:zz_something sometxt1 sometxt2
CCCCC:zz_others blahblah blehbleh
DDDDD:blihblih blohbloh
EEEEE:bluhbluh

Questo testo è diviso fondamentalmente in tre parti (la maggior parte di esso)

  • prima, prima di : , sarebbe il mio oggetto1
  • secondo, dopo : E SE inizia con zz_ , sarebbe il mio oggetto2
  • terzo, tutto il resto da quel punto in poi sarebbe un Elenco di stringhe
  • per la parte dopo : che non inizia con zz_ Userò una stringa predefinita per identificarlo.

All'inizio ho pensato di creare tre oggetti con questa struttura:

 obj1                       obj2                 obj3
    String id                 String id            String str1
    Set<String> obj2          List<obj3> list      String str2

Inoltre un oggetto principale che avrebbe mantenuto un Set<Obj1> main . Ma quando inizio a implementare questa struttura mi rendo conto che sarebbe molto difficile leggere questo in un ciclo per ottenere qualsiasi elemento al suo interno, come main.get('obj1').get('obj2').list , perché è un Set e non posso farlo.

Quindi ho finito per utilizzare una mappa come Map<String, Map<String, List<String>>> main , ma mi sembra che ci debba essere un modo migliore per farlo.

Quali sarebbero le tue raccomandazioni?

    
posta acidNoob 22.10.2014 - 00:59
fonte

1 risposta

2

Vengo da uno sfondo perl. Lì, la combinazione di avere autovivification e hash nid semplice / strutture di lista ... le mappe nidificate non sembrano troppo male se riesci a tenere la testa intorno a loro. Ma d'altra parte, non sono neanche così grandiosi ed è veramente facile per un puntatore nullo insinuarsi in altre lingue. Nei linguaggi più formali, il fatto che mostri la tua implementazione rende il refactoring un incubo . È sicuramente un codice Java meno che ottimale o idiomatico.

Quindi, abbiamo tre oggetti. Sono nidificati. E che, anche se può renderlo un po 'imbarazzante, potresti volerli effettivamente rendere nidificati classi .

One    Two          Three
AAAAAA:zz_something sometxt1 sometxt2
AAAAAA:zz_something sometxt1 sometxt2
AAAAAA:zz_someotherthing sometxt1 sometxt2

In questo esempio, avresti una classe Uno, Due e Tre. La Classe Uno avrebbe un ID associato di 'AAAAAA' e quindi altre cose. Quindi potresti avere una definizione simile a:

class One {
    String id;
    Map<String, Two> data;

    public void One() { id = null; data = new HashMap(); }

    public void build(String line) throws IllegalArgumentException {
        parse line;
        if (id == null) { id = parsedId; }
        else { throw new IllegalArgumentException("attempt to reset id"); }
        if data.contains(twoId) {
            two = data.get(twoId);
        } else {
            two = new One.Two();
            data.put(twoId, two);
        }
        two.build(line);
    }

    public static class Two {
        // ....
        private void build(String line) {
            // ....
            three = new One.Two.Three();
            three.build(line);
        }
    }
}

Tieni presente che il metodo Two.build è privato. Poiché è una classe nidificata, la classe esterna può accedere ai membri e ai metodi privati della classe interna . Ciò consente di limitare la costruzione di Due (e Tre) all'interfaccia pubblica fornita da One. Ciò impedisce ad altro codice di armeggiare con esso e di fare confusione in seguito.

Inoltre, sebbene questo non abbia tutti i metodi di accesso, verrebbero forniti tramite l'interfaccia pubblica di One in conformità con Legge di Demetra .

Sì, al di sotto di questo, questo è un Map<String, Map<String, List<String>>> - perché è quello che sono i dati. Tuttavia, è quello che non rivela la sua implementazione, o crea confusione. Sta ancora a te scrivere metodi di one.find("sometxt2") che restituisce zz_something se lo vuoi, ma rende molto più facile per la persona che usa l'oggetto farlo. Questo a sua volta rende loro meno probabilità di fare errori con il codice (anche se quella persona sei tu) e riduce il carico cognitivo permettendo uno sviluppo più rapido e meno preoccupazioni su cosa sta succedendo.

Ciò incoraggia anche codice secco in quanto non si scriverà più il codice per find(String arg) e ancora e ancora ogni volta che ne hai bisogno ... o scrivendo una classe 'helper' con metodi statici che lavorano sui dati. Quando ti ritrovi a scrivere classi SomeDataHelper o classi SomeDataUtil, probabilmente hai una classe che vuole fuggire in una forma simile a quella descritta sopra.

Come alternativa alla classe nidificata, si potrebbe usare un pacchetto per contenere le tre classi e rendere i metodi pacchetto protetto (protezione predefinita - non pubblica, o protetta o privata). Questo potrebbe rendere la serializzazione più semplice ed evitare quello che potrebbe benissimo essere un file java che è tre volte più lungo (le sue tre classi).

    
risposta data 22.10.2014 - 02:55
fonte

Leggi altre domande sui tag