Va bene andare contro la denominazione all-caps dell'enumerazione per semplificare la rappresentazione delle stringhe?

10

Diverse volte ho visto persone usare la didascalia o anche tutte le denominazioni minuscole per le costanti enum, ad esempio:

enum Color {
  red,
  yellow,
  green;
}

Questo semplifica il lavoro con la loro forma di stringa, ad esempio, se vuoi fare throw new IllegalStateException("Light should not be " + color + ".") .

Questo sembra più accettabile se l'enum è private , ma non mi piace ancora. So che posso creare un costruttore enum con un campo String, quindi eseguire l'override di toString per restituire il nome, in questo modo:

enum Color {
  RED("red"),
  YELLOW("yellow"),
  GREEN("green");

  private final String name;

  private Color(String name) { 
    this.name = name 
  }

  @Override public String toString() {
    return name; 
  }
}

Ma guarda quanto è ancora più lungo. È fastidioso continuare a fare se hai un piccolo gruppo di enumerie che vuoi mantenere semplice. Va bene usare solo formati di case non convenzionali qui?

    
posta codebreaker 19.05.2015 - 20:35
fonte

5 risposte

13

La risposta breve è, naturalmente, se si vuole rompere con le convenzioni di denominazione per quelle che sono essenzialmente costanti ... Citando da JLS :

Constant Names

The names of constants in interface types should be, and final variables of class types may conventionally be, a sequence of one or more words, acronyms, or abbreviations, all uppercase, with components separated by underscore "_" characters. Constant names should be descriptive and not unnecessarily abbreviated. Conventionally they may be any appropriate part of speech.

La lunga risposta, per quanto riguarda l'uso di toString() , è sicuramente il metodo per sovrascrivere se si desidera una rappresentazione più leggibile dei valori di enum . Citando da Object.toString() (emphasis mine):

Returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object. The result should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method.

Ora, non sono sicuro del motivo per cui alcune delle risposte sono andate alla deriva parlando della conversione di enums in-and-fro con valori String , ma mi limiterò a dare la mia opinione anche qui. Tale serializzazione dei valori di enum può essere facilmente gestita utilizzando i metodi name() o ordinal() . Entrambi sono final e quindi puoi essere sicuro dei valori restituiti fino a quando i nomi o il posizionamento dei valori non cambiano . Per me, questo è un indicatore abbastanza chiaro.

Ciò che raccolgo da quanto sopra è: oggi, potresti voler descrivere YELLOW semplicemente come "giallo". Domani, potresti descriverlo come "Pantone Minion Yellow" . Queste descrizioni devono essere restituite dalla chiamata di toString() e non mi aspetto che name() o ordinal() cambi. Se lo faccio, è qualcosa che ho bisogno di risolvere all'interno della mia base di codice o del mio team, e diventa una domanda più grande di un semplice stile di denominazione enum .

In conclusione, se tutto ciò che si intende fare è registrare una rappresentazione più leggibile dei valori enum , suggerirò comunque di attenersi alle convenzioni e quindi di sovrascrivere toString() . Se intendi serializzarli in un file di dati o in altre destinazioni non Java, hai ancora i metodi name() e ordinal() per il backup, quindi non c'è bisogno di preoccuparsi di sovrascrivere toString() .

    
risposta data 20.05.2015 - 04:11
fonte
5

Non modificare ENUM che è solo odore di codice cattivo. Lascia che un enum sia un enum e una stringa sia una stringa.

Utilizza invece un convertitore CamelCase per i valori stringa.

throw new IllegalStateException("Light should not be " + CamelCase(color) + ".");

Ci sono molte librerie open source che già risolvono questo problema per Java.

link

    
risposta data 19.05.2015 - 20:50
fonte
3

Invio di enum tra il mio codice Java e un database o un'app client, spesso finisco per leggere e scrivere i valori enum come stringhe. toString() è chiamato implicitamente quando si concatenano le stringhe. Sovraccaricare toString () su alcune enumerazioni significava che a volte potevo solo

"<input type='checkbox' value='" + MY_CONST1 + "'>"

ea volte ho dovuto ricordare di chiamare

"<input type='checkbox' value='" + MY_CONST1.name() + "'>"

che ha portato ad errori, quindi non lo faccio più. In realtà, non sovrascrivo i metodi any su Enum perché se li metti in giro con un numero sufficiente di codice client, finirai per rompere le aspettative di qualcuno.

Crea il tuo nuovo nome di metodo, come public String text() o toEnglish() o qualsiasi altra cosa.

Ecco una piccola funzione di supporto che potrebbe farti risparmiare un po 'di digitazione se hai un sacco di enumerazioni come sopra:

public static String ucFirstLowerRest(String s) {
    if ( (s == null) || (s.length() < 1) ) {
        return s;
    } else if (s.length() == 1) {
        return s.toUpperCase();
    } else {
        return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
    }
}

È sempre facile chiamare .toUpperCase () o .toLowerCase (), ma tornare a caso misto può essere complicato. Considera il colore "bleu de France". La Francia è sempre in maiuscolo, quindi potresti voler aggiungere un metodo textLower () al tuo enum se ti imbatti in questo. Quando si utilizza questo testo all'inizio di una frase, a metà di una frase, rispetto a un titolo, è possibile vedere come un singolo metodo toString() non sarà sufficiente. E questo non tocca nemmeno i caratteri che sono illegali negli identificatori di Java, o che sono difficili da digitare perché non sono rappresentati su tastiere standard, o caratteri che non hanno case (Kanji, ecc.).

enum Color {
  BLEU_DE_FRANCE {
    @Override public String textTc() { return "Bleu De France"; }
    @Override public String textLc() { return "bleu de France"; }
  }
  CAFE_NOIR {
    @Override public String textTc() { return "Café Noir"; }
  }
  RED,
  YELLOW,
  GREEN;

  // The text in title case
  private final String textTc;

  private Color() { 
    textTc = ucFirstLowerRest(this.toString());
  }

  // Title case
  public String textTc() { return textTc; }

  // For the middle of a sentence
  public String textLc() { return textTc().toLowerCase(); }

  // For the start of a sentence
  public String textUcFirst() {
    String lc = textLc();
    return lc.substring(0, 1).toUpperCase() + lc.substring(1);
  }
}

Non è così difficile utilizzarli correttamente:

IllegalStateException(color1.textUcFirst() + " clashes horribly with " +
                      color2.textLc() + "!")

Si spera che ciò dimostri anche perché l'uso di valori enum a caso misto ti deluderà. Un ultimo motivo per mantenere le maiuscole con le costanti di enumerazione dei caratteri di sottolineatura è che seguire questo principio è il Principio di Almost Astonishment. La gente se lo aspetta, quindi se fai qualcosa di diverso, dovrai sempre spiegare te stesso o trattare con le persone che usano male il tuo codice.

    
risposta data 19.05.2015 - 23:02
fonte
0

Se esiste la minima possibilità che queste rappresentazioni di stringa possano essere memorizzate in posti come database o file di testo, farle diventare vincolate alle costanti enumerate diventerà molto problematico se hai bisogno di rifattorizzare il tuo enum.

Che cosa succede se un giorno decidi di rinominare Color.White in Color.TitaniumWhite mentre ci sono file di dati là fuori che contengono "Bianco"?

Inoltre, una volta che avvii la conversione delle costanti enum in stringhe, il prossimo passo in basso sarà quello di generare stringhe che l'utente possa vedere, e il problema qui è, come sicuramente saprai, che la sintassi di java non consente spazi all'interno degli identificatori. (Non avrai mai Color.Titanium White .) Quindi, poiché probabilmente avrai bisogno di un meccanismo appropriato per generare nomi enum da mostrare all'utente, è meglio evitare inutilmente di complicare l'enumerazione.

Detto questo, puoi ovviamente andare avanti e fare ciò che hai pensato di fare, e poi ridigitare il tuo enum in un secondo momento, per passare i nomi al costruttore, quando (e se) ti imbatti nei guai.

Puoi eliminare un paio di linee dal tuo enum-con-costruttore dichiarando il name campo public final e perdendo il getter. (Cos'è questo amore che i programmatori java hanno nei confronti dei getter?)

    
risposta data 19.05.2015 - 22:20
fonte
0

Probabilmente, seguendo la convenzione di denominazione UPPERCASE si viola DRY . (E YAGNI ). ad es., nel tuo esempio di codice n. 2: "ROSSO" e "rosso" vengono ripetuti.

Quindi, segui la convenzione ufficiale o segui l'ASCIUTO? La tua chiamata.

Nel mio codice, seguirò DRY. Tuttavia, inserirò un commento sulla classe Enum, dicendo "non tutto in maiuscolo perché (spiegazione qui)"

    
risposta data 21.05.2015 - 17:32
fonte

Leggi altre domande sui tag