Enum con molte proprietà booleane


11

Attualmente sto lavorando su una webapp in cui spesso è necessario condizionare la logica del server in base alla pagina che verrà restituita all'utente.

A ciascuna pagina viene assegnato un codice di pagina di 4 lettere e questi codici di pagina sono attualmente elencati in una classe come stringhe statiche:

public class PageCodes {
    public static final String FOFP = "FOFP";
    public static final String FOMS = "FOMS";
    public static final String BKGD = "BKGD";
    public static final String ITCO = "ITCO";
    public static final String PURF = "PURF";
    // etc..
}

E spesso nel codice vediamo codice come questo ( 1 ° modulo ):

if (PageCode.PURF.equals(destinationPageCode) || PageCodes.ITCO.equals(destinationPageCode)) {
    // some code with no obvious intent
} 
if (PageCode.FOFP.equals(destinationPageCode) || PageCodes.FOMS.equals(destinationPageCode)) {
    // some other code with no obvious intent either
} 

Che è orribile da leggere perché non mostra quale proprietà comune di queste pagine ha portato l'autore del codice a metterle insieme qui. Dobbiamo leggere il codice nel iframo per capire.

Soluzione attuale

Questi messaggi ifsono stati parzialmente semplificati utilizzando elenchi di pagine dichiarate da persone diverse in classi diverse. Questo fa apparire il codice ( secondo modulo ):

private static final List<String> pagesWithShoppingCart = Collections.unmodifiableList(Arrays.asList(PageCodes.ITCO, PageCodes.PURF));
private static final List<String> flightAvailabilityPages = Collections.unmodifiableList(Arrays.asList(PageCodes.FOMS, PageCodes.FOFP));

// later in the same class
if (pagesWithShoppingCart.contains(destinationPageCode)) {
    // some code with no obvious intent
} 
if (flightAvailabilityPages.contains(destinationPageCode)) {
    // some other code with no obvious intent either
} 

... che esprime l'intento molto meglio. Ma...

Problema attuale

Il problema qui è che se aggiungiamo una pagina, in teoria avremmo bisogno di esaminare tutta la base di codice per scoprire se dobbiamo aggiungere la nostra pagina a una if()o a una lista come quella.

Anche se abbiamo spostato tutti quegli elenchi nella PageCodesclasse come costanti statiche, è comunque necessaria la disciplina da parte degli sviluppatori per verificare se la loro nuova pagina rientra in uno di quegli elenchi e aggiungerlo di conseguenza.

Nuova soluzione

La mia soluzione era quella di creare un enum (perché esiste un elenco ben noto di codici di pagina) in cui ogni pagina contiene alcune proprietà che dobbiamo impostare:

public enum Page {
    FOFP(true, false),
    FOMS(true, false),
    BKGD(false, false),
    PURF(false, true),
    ITCO(false, true),
    // and so on

    private final boolean isAvailabilityPage;
    private final boolean hasShoppingCart;

    PageCode(boolean isAvailabilityPage, boolean hasShoppingCart) {
        // field initialization
    }

    // getters
}

Quindi il codice condizionale ora appare così ( 3 ° modulo ):

if (destinationPage.hasShoppingCart()) {
    // add some shopping-cart-related data to the response
}
if (destinationPage.isAvailabilityPage()) {
    // add some info related to flight availability
}

Che è molto leggibile. Inoltre, se qualcuno ha bisogno di aggiungere una pagina, è costretto a pensare a ogni booleano e se questo è vero o falso per la sua nuova pagina.

Nuovo problema

Un problema che vedo è che ci saranno forse 10 booleani come questo, il che rende il costruttore davvero grande e potrebbe essere difficile ottenere la dichiarazione giusta quando aggiungi una pagina. Qualcuno ha una soluzione migliore?

Risposte:


13

Puoi fare un ulteriore passo avanti nell'idea e definire un enum per le funzionalità della tua pagina invece di usare booleani.

Ciò semplifica l'aggiunta / rimozione di una funzione in una pagina e rende immediatamente leggibili le definizioni della pagina anche quando ci sono 30-40 potenziali funzionalità.

public enum PageFeature {
    AVAIL_PAGE,
    SHOPPING_CART;
}

public enum Page {
    FOFP(AVAIL_PAGE),
    FOMS(AVAIL_PAGE),
    BKGD(),
    PURF(SHOPPING_CART, AVAIL_PAGE),

    private final EnumSet<PageFeature> features;

    PageCode(PageFeature ... features) {
       this.features = EnumSet.copyOf(Arrays.asList(features));
    }

    public boolean hasFeature(PageFeature feature) {
       return features.contains(feature);
    }
 }

Ci ho pensato, ma qui lo sviluppatore non è costretto a dare una risposta a tutte le domande "è una pagina di disponibilità?", "Ha un carrello della spesa?" ecc. Quando ce ne sono molti, te ne dimentichi facilmente uno.
Joffrey,

5
@Joffrey Quando ci pensi, avere dieci booleani non li costringe nemmeno a dare una risposta, almeno non una risposta a cui pensano. Lo scenario più probabile è che copieranno semplicemente la definizione di un'altra pagina o lasceranno semplicemente che l'IDE riempia tutti i parametri false, quindi ne modifichino uno o due (probabilmente quello sbagliato, poiché è così difficile tenere traccia). Non esiste una protezione perfetta dagli stupidi e arriva un punto in cui devi fidarti dei tuoi sviluppatori per fare la cosa giusta.
biziclop,

Giusto, non ci ho pensato in questo modo :) E non credo che il piccolo extra "a prova di stupido" dato dal booleano valga il degrado della sensibilità, quindi probabilmente andrò con la soluzione vararg. Grazie per la tua comprensione!
Joffrey,

1
Buona soluzione, votata. Anche se la parte di me che ha codificato su 6502s vuole stipare tutto a pezzi. :-)
user949300

@ user949300 la prima soluzione simile a vararg a cui ho pensato era in realtà un po 'maschere :) ma un vero vararg con un tipo enum è più pulito
Joffrey
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.