¿Es la sensibilidad de orden de enumeración un antipatrón?

7

¿Es un antipatrón depender de un orden particular de las declaraciones de instancia de una enumeración? Por ejemplo, considere:

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

Estos puntos están en orden en el sentido de las agujas del reloj . ¿Hay alguna buena razón para que el código no se base en este hecho? Más específicamente, es "correcto" confiar en este código:

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

"OK" aquí es "mejor práctica", incluyendo evitar una bomba de tiempo si alguien agregó inocentemente instancias para los puntos de los cuartos, lo que puede (o no) romper la intención del significado de "derecho".

Si "no está bien", ¿está menos "no está bien" si dicho código está restringido a ser interno de la clase enum?

    
pregunta Bohemian 26.07.2015 - 06:49

3 respuestas

13

También diría que, en su mayoría, respondiste la pregunta por tu cuenta. No lo implementaría de esa manera porque es frágil.

Al tener ese código como parte de la clase enum en sí, es ciertamente mejor porque el problema está aislado del detalle de implementación de la enumeración. Para el problema en cuestión, creo que esa solución sería "lo suficientemente buena" y, por lo tanto, aceptable.

Al asumir que la enumeración se usará con frecuencia y es probable que se extienda en el futuro, usaría las funciones avanzadas de enumeración de Java, como campos y métodos:

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

Los enums de Java son realmente poderosos y debo decir que los extraño mucho al programar C #.

    
respondido por el Stefan Sieber 26.07.2015 - 09:23
2

Tiene sentido colocar la enumeración en algún orden lógico, por la única razón de darles sentido. Por ejemplo, ¿no habrías puesto un número de meses con febrero después de octubre? (pregunta retórica).

En varios idiomas, las enumeraciones pueden tratarse como si tuvieran un pedido, al igual que en el ejemplo que proporciona. Por esa razón, tiene mucho sentido ponerlos en orden lógico o, quizás más correctamente, en el "orden del mundo real".

En el ejemplo que proporciona, no todas las culturas necesarias toman las cosas en el orden "de las agujas del reloj", de hecho, algunas culturas utilizan inherentemente el orden "de las agujas del reloj". En estas culturas, encontrará enumeraciones que representan la dirección de la brújula para estar en el orden 'contrahorario'. Algo así como los meses que no tienen una idea en el sentido de las agujas del reloj o en sentido contrario a las agujas del reloj todavía se encuentran en el orden ordinal.

Otra consideración sobre el orden viene cuando se considera la clasificación. Si clasificaría el Norte antes que el Este, ese debería ser el orden utilizado para alinearse con los algoritmos de clasificación predeterminados que podrían ordenar las cosas usando la enumeración como la clave.

Cuando escriba un código, debe tener en cuenta sus propias expectativas o las personas que podrían usar su código. Si sabe y espera que sus enumeraciones sigan un orden en el sentido de las agujas del reloj, entonces debe usarlo como la mejor práctica. Si está escribiendo un código para que lo utilicen las personas que normalmente usan el orden en sentido contrario a las agujas del reloj, es posible que desee ordenarlos de esa manera. También se podría argumentar que, dado que la mayoría de las culturas usan la rotación en el sentido de las agujas del reloj, entonces eso es lo que debe usar y en lo que debe confiar.

No importa lo que haga, debe mantenerse un cierto orden de orden y debe mantenerse constante en todo su código, si lo usa en el sentido de las agujas del reloj, entonces utilícelo en todas partes. Sin embargo, no haría algo como enumeración {Norte, Sur, Este, Oeste} ya que no tiene un ordenamiento típico.

    
respondido por el ydobonebi 26.07.2015 - 08:31
2

Creo que casi has respondido tu propia pregunta :)

La razón principal para no confiar en los códigos ordinales externos al enum, es lidiar con el cambio . Como ha señalado, agregar un punto de referencia de NorthEast podría alterar el significado de su cálculo 'toRightIndex' . Si ha escrito un código que se basa en el ordinal, es probable que deba cambiarlo. Por lo tanto, tiene sentido no confiar en lo ordinal fuera de la enumeración.

Dicho esto, no puedo ver ningún inconveniente práctico en el uso de los ordinales en un método interno de la enumeración, siempre que Para las personas que mantienen y usan el código, el ordinal representa un orden fácil de entender que tiene sentido en el mundo real.

Un consejo del javadocs para Enum :

  

public final int ordinal()
  Devuelve el ordinal de esta constante de enumeración (su posición en su declaración de enumeración, donde a la constante inicial se le asigna un ordinal de cero).   La mayoría de los programadores no tendrán ningún uso para este método.   Está diseñado para ser utilizado por estructuras de datos sofisticadas basadas en enumeración, como EnumSet y EnumMap.

    
respondido por el Rajiv 26.07.2015 - 08:43

Lea otras preguntas en las etiquetas