Dati statici per enum: costruttore, impostato in initialiser o override getter?

3

Ho un enum con > 10 articoli ciascuno con 8 proprietà statiche. Esempio di esempio:

enum JavaTypes {
    INTEGER,
    BOOLEAN,
    STRING,
    ...;

    boolean isPrimitive() {
    }

    boolean isNumeric() {
    }
    ...
}

Sto cercando di trovare lo stile più leggibile e manutenibile (facile da aggiungere).

  1. I getter di override standard non funzionano molto bene, poiché ogni enum body diventa piuttosto lungo ed è difficile confrontare la stessa proprietà tra gli elementi.

  2. Impostazione di tutte le proprietà nel costruttore. Afflitto dal problema di quale argomento è quale. Ho provato ad allineare gli argomenti in una tabella, ma ho vinto il limite di 120 caratteri che abbiamo.

  3. Campi non finali e inizializzatore di istanze: ad es.

    INTEGER {{ primitive = true; numeric = true; }},
    
    boolean primitive, numeric;
    
    boolean isPrimitive() {
        return primitive;
    }
    

    Questo sembra un po 'sporco però

3 è accettabile? C'è qualche opzione migliore.

Modifica:

Giusto per chiarire, non tutte le proprietà sono booleane.

    
posta billc.cn 20.01.2017 - 16:56
fonte

2 risposte

5

Un'altra opzione sarebbe quella di usare un secondo enum e un costruttore di varargs insieme a un EnumSet :

enum JavaType {
    INTEGER(TypeProperty.PRIMITIVE, TypeProperty.NUMERIC),
    BOOLEAN(TypeProperty.PRIMITIVE),
    STRING(),
    /* ... */;

    private EnumSet<TypeProperty> properties;
    private JavaType(TypeProperty... properties) {
        this.properties = EnumSet.copyOf(Arrays.asList(properties));
    }

    public boolean isPrimitive() {
        return properties.contains(TypeProperty.PRIMITIVE);
    }

    public boolean isNumeric() {
        return properties.contains(TypeProperty.NUMERIC);
    }
    /* ... */

    private enum TypeProperty {
        PRIMITIVE,
        NUMERIC,
        /* ... */
    }
}

Questo ha il vantaggio di non richiedere di specificare un gruppo di valori falsi in un costruttore (il problema con # 2), ma non richiede un gruppo di classi interne per ogni enumerazione. Il TypeProperty enum non ha nemmeno bisogno di essere visibile al di fuori di JavaType perché funzioni.

In alternativa, TypeProperty può essere reso pubblico e può esserci un metodo is(TypeProperty) . Che tu lo voglia o no dipende da come prevedi di utilizzare JavaType ; può essere conveniente esporlo (ad es. per creare un metodo allWith(TypeProperty) ) ma se non è qualcosa che potresti usare all'esterno, non esporlo. Che lo vogliate o meno dipende da come userete il vostro enum.

Se viene visualizzato TypeProperty , potrebbe essere combinato con un importazione statica in modo da poter semplicemente fare riferimento ai nomi delle costanti enum all'interno del tipo. Questo può aiutare con la leggibilità se usato bene, ma attenzione. TypeProperty deve essere esposto per essere importato, sebbene possa ancora essere per lo più privato se necessario (può comunque essere contenuto in JavaType se necessario, non può essere solo private ). Ecco un esempio:

package com.example;
import static com.example.TypeProperty.*;

enum JavaType {
    INTEGER(PRIMITIVE, NUMERIC),
    BOOLEAN(PRIMITIVE),
    STRING(),
    /* ... */;

    private EnumSet<TypeProperty> properties;
    private JavaType(TypeProperty... properties) {
        this.properties = EnumSet.copyOf(Arrays.asList(properties));
    }

    public boolean isPrimitive() {
        return properties.contains(PRIMITIVE);
    }

    public boolean isNumeric() {
        return properties.contains(NUMERIC);
    }
    /* ... */
}

enum TypeProperty {
    PRIMITIVE,
    NUMERIC,
    /* ... */
}

Just to clarify, not all of the properties are booleans.

Se hai alcune proprietà non booleane, puoi metterle all'inizio del costruttore e seguirle con il parametro varargs. È ancora possibile eseguire il problema senza etichetta, ma ti consente di organizzarlo di più. Di 'qualcosa del tipo:

enum JavaType {
    INTEGER("int", Integer.class, TypeProperty.PRIMITIVE, TypeProperty.NUMERIC),
    BOOLEAN("boolean", Boolean.class, TypeProperty.PRIMITIVE),
    STRING("String", String.class),
    /* ... */;

    private String name;
    private Class<?> representationClass;
    private EnumSet<TypeProperty> properties;
    private JavaType(String name, Class<?> representationClass, TypeProperty... properties) {
        this.name = name;
        this.representationClass = representationClass;
        this.properties = EnumSet.copyOf(Arrays.asList(properties));
    }
    /* ... code from before ... */
}

Se hai molte proprietà non booleane, allora diventa molto più difficile organizzarle. A quel punto, l'approccio n. 3 potrebbe essere più ragionevole, o in alternativa potresti combinare l'approccio n. 1 e i parametri vararg.

    
risposta data 20.01.2017 - 17:31
fonte
1

Non sono un grande fan delle enumerazioni sull'uso del pattern Typesafe Enum per questo motivo, tra gli altri. Il vantaggio principale nell'usare la funzione enum incorporata è che puoi usarli nelle istruzioni switch ma io preferisco comunque il polimorfismo.

Ad ogni modo, un altro modo per fare ciò che usa la "commutabilità" delle enumerazioni è il seguente. È un po 'brutto, ma lo sono anche le enumerazioni in generale:

public class EnumHolder
{
  public enum JavaTypes {
    INTEGER,
    BOOLEAN,
    STRING;

    boolean isPrimitive() {
      return EnumHolder.isPrimitive(this);
    }
  }

  private static final boolean isPrimitive(JavaTypes type) {
    switch (type) {
      case INTEGER:
      case BOOLEAN:
        return true;
      default:
        return false;
    }
  }
}
    
risposta data 20.01.2017 - 18:19
fonte

Leggi altre domande sui tag