Pregunta

Mantengo un gran archivo de documentos y a menudo uso campos de bits para registrar el estado de mis documentos durante el procesamiento o al validarlos. Mi código heredado simplemente usa constantes INT estáticas como:

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

Esto hace que sea bastante fácil indicar que el estado se encuentra un documento, estableciendo las banderas apropiadas. Por ejemplo:

status = DOCUMENT_STATUS_NO_TIF_FILE | DOCUMENT_STATUS_NO_PDF_FILE;

Dado que el enfoque de usar constantes estáticas es una mala práctica y, debido a que me gustaría mejorar el código, estaba buscando usar enums para lograr lo mismo. Hay algunos requisitos, uno de ellos es la necesidad de guardar el estado en una base de datos como tipo numérico. Por lo tanto, es necesario transformar las constantes de enumeración en un valor numérico. A continuación se muestra mi primer enfoque y me pregunto si esta es la forma correcta de hacerlo.

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);

    }

}
¿Fue útil?

Solución

Su enfoque es exactamente la forma de hacerlo.

Otros consejos

En lugar de definir los parámetros del constructor, simplemente puede usar el interno ordinal() valor para calcular esto.

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();
    } 

}

Tenga en cuenta que ahora debe abstenerse de reordenar, insertar (que no sea al final) o eliminar entradas, de lo contrario, los valores de la bandera cambiarán y el significado de su contenido de la base de datos cambiará.

Una manera un poco mejor sería almacenar el resultado de 1 << this.ordinal() en un campo cuando se construyen los valores enum. De esta manera, no tiene que proporcionar cada valor manualmente, y el indicador solo se calcula una vez.

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();
  } 
}

Editar: podría ser útil tener el método ISFlagSet también.

No le dé a sus enums valores. Usa un EnumSet para combinarlos y usar Enum.ordinal() cuando persiste para convertir a/desde un solo entero. También puedes encontrar Class.getEnumConstants() Útil al reconstruir el conjunto del entero.

He hecho una biblioteca completa para este problema:http://claude-martin.ch/enumbitset/

El objetivo principal era almacenar conjuntos de tipos de Enum en bitfields. Pero también es compatible con otros tipos.

Con esto no necesitaría ningún método adicional como su "GetStatusFlags ()". Se puede usar en cualquier tipo de enum existente simplemente agregando la interfaz Enumbitsethelper (se usa como un "rasgo"). Cada constante de enumia puede crear un "enumbitset" que tiene todos los métodos de enumset y bitset de Java. Luego puede trabajar con estos conjuntos de constantes enum y convertirlos en valores de bitfield.

Admite muchos formatos como BigInteger y Long para almacenar fácilmente el valor en un campo un poco. Pero tenga en cuenta que esto solo funciona con Java versión 8 y más nuevo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top