L'accoppiamento di un'interfaccia gonfia con un Enum è una buona idea?

3

Al lavoro abbiamo un'interfaccia che si sta gonfiando. L'interfaccia è progettata per essere facilmente implementata da un oggetto immutabile. Quindi sembra qualcosa del genere:

//there is no behavior here, just data access
interface DataBlock {
    String name();
    Integer idNumber();
    Double score();
    Instant time();
    //...12 additional methods with arbitrary return types
} 

Ci sono diversi punti nel codice in cui sarebbe utile rappresentare i valori all'interno di DataBlock come una mappa. Ad esempio, quando si implementa un costruttore o uno stabilimento.

La mia domanda iniziale era: Quale dovrebbe essere il tipo generico della mappa?

La codifica dei nomi dei metodi di interfaccia ha prodotto: Map<String, Object> dataBlockAsMap = Data . Non mi piaceva questa opzione perché è facile digitare il nome del metodo in modo errato. Ad esempio, fallirà silenziosamente se qualcuno scrive map.get("iDNumber") invece di map.get("idNumber") .

Attualmente mi sto appoggiando a Map<DataBlockField, Object> dove DataBlockField è un enum con un tipo per ogni metodo nell'interfaccia. L'aspetto positivo di questo approccio è (1) che ogni valore enum può "conoscere" il suo tipo richiesto e (2) rende facile scrivere operazioni in batch come:

public static Map<DataBlockField, Object> asMap(DataBlock block) {
    Map<DataBlockField, Object> map = new HashMap<>();
    for(DataBlockField field : DataBlockField.values()) {
         //enum helps extract a value from datablock
         map.put(field, field.getFrom(block));
    }
}

//and

public static String toString(DataBlock block) {
    StringBuilder sb = new StringBuilder();
    for(DataBlockField field : DataBlockField.values()) {
         //enum helps extract a value from datablock
         sb.append(field.getFrom(block)); 
    }
}

La mia domanda è: l'introduzione di questa "interfaccia backed enum" è una buona idea? Chiedo perché potrei mancare qualcosa. In apparenza questa "enum backed interface" è vagamente simile al Builder Pattern. Tuttavia, vedo Builder a destra e a sinistra. Eppure non ho mai visto un enum scritto per rispecchiare i metodi in un'interfaccia.

Mi manca qualcosa qui?

    
posta Ivan 12.10.2016 - 17:06
fonte

1 risposta

2

Penso che usare enum in questo modo sia un progetto ragionevole.

L'unico inconveniente è il requisito non necessariamente ovvio per la manutenzione del tuo enum quando l'interfaccia viene mantenuta / estesa.

Alternative come spunti di riflessione:

(1) forniscono una classe base astratta (invece di un'interfaccia) che fornisce sia i campi che la serializzazione. (Questo potrebbe non essere pratico dato un codice esistente e la limitazione dell'ereditarietà singola.)

(2) usa la riflessione per enumerare i metodi nell'interfaccia. In questo modo è possibile scrivere metodi che ottengono lo stesso risultato dell'enumerazione, anche se possono rilevare qualsiasi metodo nell'interfaccia. (Puoi rabbrividire usando il riflesso, ma potresti farlo in un modo più statico di quanto si possa pensare, dal momento che tutto ciò su cui devi riflettere sono i metodi dell'interfaccia, una volta, staticamente e salvalo, piuttosto che su ogni oggetto dato Continueresti comunque a fare il .invoke() dinamico.)

(3) se fosse C # (non conosco l'equivalente Java, ma vedi qui ) Suggerirei inoltre di utilizzare i modelli (T4) o alcuni strumenti di generazione automatica del codice o un programma di build time per generare sia il codice di interfaccia che il codice enumer, in modo che rimangano sincronizzati automaticamente. Nell'input di template / DSL, devi elencare i campi e i loro tipi, quindi lo strumento genererebbe sia l'interfaccia che l'enumerazione che fornisce gli accessor .getFrom() .

    
risposta data 06.06.2017 - 02:26
fonte

Leggi altre domande sui tag