Question

Je maintiens une grande archive de documents et je l'utilise souvent des champs de bits pour enregistrer l'état de mes documents au cours du traitement ou lors de leur validation. Mon code hérité utilise simplement des constantes int statiques telles que:

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

Il est donc assez facile d'indiquer l'état d'un document est, en définissant les indicateurs appropriés. Par exemple:

status = DOCUMENT_STATUS_NO_TIF_FILE | DOCUMENT_STATUS_NO_PDF_FILE;

Depuis l'approche de l'utilisation des constantes statiques est mauvaise pratique et parce que je voudrais améliorer le code, je cherchais à utiliser énumérations pour obtenir le même. Il y a quelques exigences, l'un d'entre eux étant la nécessité de sauvegarder l'état dans une base de données en tant que type numérique. Donc, il est nécessaire de transformer les constantes d'énumération à une valeur numérique. Voici ma première approche et je me demande si cela est la bonne façon d'aller à ce sujet?

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

    }

}
Était-ce utile?

La solution

votre approche est exactement la façon de le faire.

Autres conseils

Au lieu de définir les paramètres du constructeur, vous pouvez simplement utiliser la valeur ordinal() interne pour calculer cela.

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

}

S'il vous plaît noter que maintenant, vous devriez vous abstenir de réordonnancement, l'insertion (autre que, à la fin) ou de supprimer des entrées, sinon les valeurs de drapeau changeront, et le sens du contenu de votre base de données changera.

Une façon un peu mieux serait de stocker le résultat de 1 << this.ordinal() dans un domaine où les valeurs enum sont construites. De cette façon, vous ne devez pas fournir à chaque valeur manuellement, et le drapeau n'est calculé une fois.

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: il pourrait être utile d'avoir la méthode isFlagSet aussi bien.

Ne donnez pas vos valeurs énumérations. Utilisez un EnumSet pour les combiner, et à l'utilisation lors de la persistance Enum.ordinal() pour convertir vers / à partir d'un unique entier. Vous pouvez également trouver Class.getEnumConstants() utile lors de la reconstruction de l'ensemble de l'entier.

Je l'ai fait une bibliothèque complète de ce problème: http://claude-martin.ch/enumbitset/

Le but principal était de jeux de stocker des types enum dans bitfields. Mais il soutient également d'autres types.

Avec cela, vous auriez pas besoin des méthodes supplémentaires comme vos « getStatusFlags () ». Il peut être utilisé sur tout type enum existant en ajoutant simplement l'interface EnumBitSetHelper (il est utilisé comme un « trait »). Chaque constante enum peut alors créer un « EnumBitSet » qui a toutes les méthodes de EnumSet et BitSet de Java. Ensuite, vous pouvez travailler avec ces ensembles de constantes de ENUM et les convertir en valeurs BITFIELD.

Il supporte de nombreux formats tels que BigInteger et long pour stocker facilement la valeur dans un champ de bits. Mais notez que cela ne fonctionne qu'avec Java version 8 et plus récente.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top