La sensibilità all'ordine enum è un antipattern?

7

È un anti-pattern che dipende da un particolare ordine delle dichiarazioni di istanze di un enum? Ad esempio, considera:

public enum CompassPoint {
    North,
    East,
    South,
    West;
}

Questi punti si trovano nell'ordine orario . C'è una buona ragione per non fare affidamento sul codice su questo fatto? Più specificamente, è "OK" fare affidamento su questo codice:

 CompassPoint from;
 int toRightIndex = (from.ordinal() + 1) % CompassPoint.values();
 CompassPoint toRight = CompassPoint.values()[toRightIndex];

"OK" qui è la "migliore pratica", compresa quella di evitare una bomba a tempo se qualcuno ha aggiunto innocentemente delle istanze per i punti quarto, il che può (o non può) rompere l'intenzione del significato di "a destra".

Se "non OK", è meno "non OK" se tale codice è limitato ad essere interno alla classe enum?

    
posta Bohemian 26.07.2015 - 06:49
fonte

3 risposte

13

Direi anche che per la maggior parte hai risposto alla domanda da solo. Non lo implementerei in questo modo perché è fragile.

Quando si ha quel codice come parte della stessa classe enum, è certamente meglio perché il problema è isolato dai dettagli di implementazione dell'enum. Per il problema a portata di mano penso che la soluzione sarebbe "abbastanza buona" e quindi accettabile.

Se si presuppone che l'enumerazione verrà utilizzata frequentemente ed è probabile che venga estesa in futuro, farei uso delle funzionalità avanzate di enum Java come campi e metodi:

    public enum CompassDirection {
    NORTH(0),
    EAST(90),
    SOUTH(180),
    WEST(270);

    private final double degreesFromNorth;

    CompassDirection(double degreesFromNorth) {
        this.degreesFromNorth = degreesFromNorth;
    }

    public CompassDirection directionToRight(){
        directionForDegreesFromNorth(degreesFromNorth + 90);
    }

    public CompassDirection directionToLeft(){
        directionForDegreesFromNorth(degreesFromNorth - 90);
    }

    public CompassDirection directionForDegreesFromNorth(double degreesFromNorth){
        double normalizedDegrees = Math.floorMod(degreesFromNorth, 360);
        for(CompassDirection direction : CompassDirection.values()){
            if(direction.degreesFromNorth == normalizedDegrees){
                return direction;
            }
        }

        throw new Exception("No matching direction could be found");
    }
}

Le enumerazioni Java sono molto potenti e devo dire che mi mancano molto quando programmate C #.

    
risposta data 26.07.2015 - 09:23
fonte
2

Ha senso mettere enum in un ordine logico, se non altro per motivi di dare un senso a loro. Ad esempio, non avresti messo un enum di mesi con febbraio dopo ottobre? (domanda retorica).

In diverse langues le enumerazioni possono essere trattate come se avessero un ordine, proprio come nell'esempio che fornisci. Per questo motivo ha molto senso inserirli in un ordine logico o forse più correttamente nel "mondo reale".

Dall'esempio fornito, non tutte le culture necessarie prendono le cose in senso orario, infatti alcune culture usano intrinsecamente l'ordine 'antiorario'. In queste culture troverai enumerazioni che rappresentano le cose in cui la direzione della bussola è in senso 'antiorario'. Qualcosa come i mesi che non hanno un'idea in senso orario / antiorario si trovano ancora nell'ordine ordinale.

Un'altra considerazione sull'ordine arriva quando si considera l'ordinamento. Se ordinassi il Nord prima di Est, questo dovrebbe essere l'ordine utilizzato per rientrare in linea con gli algoritmi di ordinamento predefiniti che potrebbero ordinare le cose usando l'enum come chiave.

Quando scrivi il codice dovresti prendere in considerazione le tue aspettative o coloro che potrebbero usare il tuo codice. Se sai e ti aspetti che le tue enumerazioni seguano l'ordine in senso orario, dovresti usarle come best practice. Se stai scrivendo il codice che deve essere usato da persone che tipicamente usano l'ordine in senso antiorario, puoi invece ordinarli in quel modo. Si potrebbe anche sostenere che dal momento che la maggior parte delle culture utilizza la rotazione in senso orario, allora è quello che dovresti usare e fare affidamento su.

Non importa quello che fai, un certo senso dell'ordine dovrebbe essere mantenuto e dovrebbe essere mantenuto coerente su tutto il tuo codice, se usi in senso orario, quindi usalo ovunque. Tuttavia, non farei qualcosa come enum {Nord, Sud, Est, Ovest} in quanto non ha ordinamenti tipici.

    
risposta data 26.07.2015 - 08:31
fonte
2

Penso che tu abbia risposto alla tua stessa domanda:)

Il motivo principale per non fare affidamento sull'ordinale nel codice esterno all'enum, è affrontare il cambiamento . Come hai fatto notare, l'aggiunta di un punto di bussola NorthEast potrebbe alterare il significato del tuo calcolo 'toRightIndex' . Se hai scritto un codice che si basa sull'ordinale, probabilmente avrà bisogno di cambiare. Quindi ha senso non fare affidamento sull'ordinale al di fuori dell'enum.

Detto questo, non vedo alcun inconveniente pratico nell'usare l'ordinale in un metodo interno all'enum, a condizione che persone che mantengono e usano il codice, l'ordinale rappresenta un ordine facilmente comprensibile che ha senso nel mondo reale.

Un piccolo consiglio da javadocs per Enum :

public final int ordinal()
Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero). Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data structures, such as EnumSet and EnumMap.

    
risposta data 26.07.2015 - 08:43
fonte

Leggi altre domande sui tag