Domanda

I mantenere un grande archivio di documenti e che uso spesso campi di bit per registrare lo stato dei miei documenti durante la lavorazione o quando loro validazione. Il mio codice legacy utilizza semplicemente le costanti static int come ad esempio:

static int DOCUMENT_STATUS_NO_STATE = 0
static int DOCUMENT_STATUS_OK = 1
static int DOCUMENT_STATUS_NO_TIF_FILE = 2
static int DOCUMENT_STATUS_NO_PDF_FILE = 4

In questo modo è abbastanza facile per indicare lo stato di un documento è in, impostando i flag appropriati. Ad esempio:

status = DOCUMENT_STATUS_NO_TIF_FILE | DOCUMENT_STATUS_NO_PDF_FILE;

Dal momento che l'approccio di utilizzare costanti statiche è cattiva pratica e perché vorrei migliorare il codice, che stava cercando di utilizzare enumerazioni per ottenere lo stesso. Ci sono alcuni requisiti, uno dei quali è la necessità di salvare lo stato in un database come un tipo numerico. Quindi v'è la necessità di trasformare le costanti di enumerazione per un valore numerico. Qui di seguito è il mio primo approccio e mi chiedo se questo è il modo corretto di andare su questo?

class DocumentStatus{

    public enum StatusFlag {

        DOCUMENT_STATUS_NOT_DEFINED(1<<0),
        DOCUMENT_STATUS_OK(1<<1), 
        DOCUMENT_STATUS_MISSING_TID_DIR(1<<2),
        DOCUMENT_STATUS_MISSING_TIF_FILE(1<<3),
        DOCUMENT_STATUS_MISSING_PDF_FILE(1<<4),
        DOCUMENT_STATUS_MISSING_OCR_FILE(1<<5),
        DOCUMENT_STATUS_PAGE_COUNT_TIF(1<<6),
        DOCUMENT_STATUS_PAGE_COUNT_PDF(1<<7),
        DOCUMENT_STATUS_UNAVAILABLE(1<<8);


        private final long statusFlagValue;

        StatusFlag(long statusFlagValue) {
            this.statusFlagValue = statusFlagValue;
        }

        public long getStatusFlagValue(){
            return statusFlagValue;
        } 

       }


    /**
     * Translates a numeric status code into a Set of StatusFlag enums
     * @param numeric statusValue 
     * @return EnumSet representing a documents status
     */
    public EnumSet<StatusFlag> getStatusFlags(long statusValue) {
        EnumSet statusFlags = EnumSet.noneOf(StatusFlag.class);
        StatusFlag.each { statusFlag -> 
            long flagValue = statusFlag.statusFlagValue
            if ( (flagValue&statusValue ) == flagValue ) {
               statusFlags.add(statusFlag);
            }
        }
        return statusFlags;
    }


    /**
     * Translates a set of StatusFlag enums into a numeric status code
     * @param Set if statusFlags
     * @return numeric representation of the document status 
     */
    public long getStatusValue(Set<StatusFlag> flags) {
        long value=0;
        flags.each { statusFlag -> 
            value|=statusFlag.getStatusFlagValue() 
        }
        return value;
    }

     public static void main(String[] args) {

        DocumentStatus ds = new DocumentStatus();
        Set statusFlags = EnumSet.of(
            StatusFlag.DOCUMENT_STATUS_OK,
            StatusFlag.DOCUMENT_STATUS_UNAVAILABLE);

        assert ds.getStatusValue( statusFlags )==258 // 0000.0001|0000.0010

        long numericStatusCode = 56;
        statusFlags = ds.getStatusFlags(numericStatusCode);

        assert !statusFlags.contains(StatusFlag.DOCUMENT_STATUS_OK);
        assert statusFlags.contains(StatusFlag.DOCUMENT_STATUS_MISSING_TIF_FILE);
        assert statusFlags.contains(StatusFlag.DOCUMENT_STATUS_MISSING_PDF_FILE);
        assert statusFlags.contains(StatusFlag.DOCUMENT_STATUS_MISSING_OCR_FILE);

    }

}
È stato utile?

Soluzione

il tuo approccio è esattamente il modo per farlo.

Altri suggerimenti

Invece di definire parametri del costruttore, si può semplicemente utilizzare il valore ordinal() interno per calcolare questo.

public enum StatusFlag {

    DOCUMENT_STATUS_NOT_DEFINED,
    DOCUMENT_STATUS_OK, 
    DOCUMENT_STATUS_MISSING_TID_DIR,
    DOCUMENT_STATUS_MISSING_TIF_FILE,
    DOCUMENT_STATUS_MISSING_PDF_FILE,
    DOCUMENT_STATUS_MISSING_OCR_FILE,
    DOCUMENT_STATUS_PAGE_COUNT_TIF,
    DOCUMENT_STATUS_PAGE_COUNT_PDF,
    DOCUMENT_STATUS_UNAVAILABLE;


    public long getStatusFlagValue(){
        return 1 << this.ordinal();
    } 

}

Si noti che ora si dovrebbe astenersi dal riordino, l'inserimento (diverso alla fine) o l'eliminazione di voci, altrimenti i valori di bandiera cambieranno, e il significato dei tuoi contenuti del database cambierà.

Un modo leggermente migliore potrebbe essere quella di memorizzare il risultato di 1 << this.ordinal() in un campo in cui i valori enum sono costruiti. In questo modo, non è necessario fornire manualmente ogni valore, e la bandiera viene calcolato solo una volta.

public enum StatusFlag {

  DOCUMENT_STATUS_NOT_DEFINED,
  DOCUMENT_STATUS_OK, 
  DOCUMENT_STATUS_MISSING_TID_DIR,
  DOCUMENT_STATUS_MISSING_TIF_FILE,
  DOCUMENT_STATUS_MISSING_PDF_FILE,
  DOCUMENT_STATUS_MISSING_OCR_FILE,
  DOCUMENT_STATUS_PAGE_COUNT_TIF,
  DOCUMENT_STATUS_PAGE_COUNT_PDF,
  DOCUMENT_STATUS_UNAVAILABLE;

  public final int flag;

  StatusFlag() { 
    this.flag = 1 << this.ordinal();
  } 
}

EDIT: potrebbe essere utile avere metodo isFlagSet pure.

Non dare il tuo valori enums. Utilizzare un EnumSet combinarle, e l'uso Enum.ordinal() quando persiste per convertire a / da un singolo intero. Si potrebbe anche trovare Class.getEnumConstants() utile quando ricostruire il set dal numero intero.

Ho fatto una libreria completa per questo problema: http://claude-martin.ch/enumbitset/

L'obiettivo principale era quello di memorizzare set di tipi enum in campi di bit. Ma supporta anche altri tipi.

Con questo non avrebbe bisogno tutti i metodi extra come i vostri "getStatusFlags ()". Può essere utilizzato su qualsiasi tipo enum esistente semplicemente aggiungendo l'interfaccia di EnumBitSetHelper (è usato come un "trait"). Ogni costante enum può quindi creare un "EnumBitSet", che ha tutti i metodi di EnumSet e BitSet di Java. Poi si può lavorare con questi insiemi di costanti enum e convertirli in valori BITFIELD.

Supporta molti formati come BigInteger e lunghi a facilmente memorizzare il valore in un campo di bit. Ma si noti che questo funziona solo con Java versione 8 e successive.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top