es un modificador (esto) antipatrón o una mala práctica en Java para Enums?

7

En el trabajo, me encontré con un problema para ver cómo las enumas están creciendo y almacenando las lógicas de negocios. A medida que crecieron, los constructores crecieron mucho. En un momento me di cuenta de que, en lugar de agregar el décimo parámetro booleano (y que ya tenía otros parámetros distintos del booleano) en el constructor, y expandir todas las inicializaciones con un parámetro adicional, haré un nuevo, pero no realmente utilizado - construcción con el propósito de la legibilidad del código.

Aquí hay un ejemplo, así que en lugar de:

public enum A {
  A1(true, true, false),
  A2(true, false, true),
  A3(false, false, false);

private A(boolean firstParam, boolean secondParam, boolean thirdParam){
    ... usual constructor ...
}

... getters

Así que en vez hice lo siguiente:

public enum A {
  A1,
  A2,
  A3;

... no need for special constructor

public boolean isFirstParam(){
  switch(this){
    case A1:
    case A2:
      return true;
    default:
      return false;
  }
}

public boolean isSecondParam(){
  switch(this){
    case A1:
      return true;
    default:
      return false;
  }
}

public boolean isThirdParam(){
  switch(this){
    case A2:
      return true;
    default:
      return false;
  }
}

Hasta el momento a quien la haya usado le gusta. Pero algunos colegas que no lo sabían tuvieron malas reacciones:

  • Sonar no estaba contento de ver la declaración del interruptor (esto).
  • No les gustó el concepto en sí.

Mi pregunta es: ¿hay alguna razón real por la que no debería usarla? Es mucho más fácil de mantener cuando tienes enumeraciones complejas. Creo que no usé nada especial, solo cambié la enumeración, solo en un lugar especial. Estoy en lo correcto?

    
pregunta CsBalazsHungary 18.11.2015 - 15:31

2 respuestas

13

La otra alternativa es reemplazar los métodos por instancia:

public enum A {
  A1{
    @Override public boolean isFirstParam(){ return true; }
    @Override public boolean isSecondParam(){ return true; }
    @Override public boolean isThirdParam(){ return false; }
  },
  A2{
    @Override public boolean isFirstParam(){ return true; }
    @Override public boolean isSecondParam(){ return false; }
    @Override public boolean isThirdParam(){ return false; }
  },
  A3{
    @Override public boolean isFirstParam(){ return false; }
    @Override public boolean isSecondParam(){ return false; }
    @Override public boolean isThirdParam(){ return false; }
  };

  public abstract boolean isFirstParam();
  public abstract boolean isSecondParam();
  public abstract boolean isThirdParam();
}

enlace dice esto:

  

La idea de agregar comportamiento a las constantes de enumeración se puede tomar un paso   promover. Puedes dar a cada enumeración constante un comportamiento diferente para algunos   método. Una forma de hacer esto activando la constante de enumeración.   Aquí hay un ejemplo con una enumeración cuyas constantes representan las cuatro   operaciones aritméticas básicas, y cuyo método eval realiza el   operación:

public enum Operation {
    PLUS, MINUS, TIMES, DIVIDE;

    // Do arithmetic op represented by this constant
    double eval(double x, double y){
        switch(this) {
            case PLUS:   return x + y;
            case MINUS:  return x - y;
            case TIMES:  return x * y;
            case DIVIDE: return x / y;
        }
        throw new AssertionError("Unknown op: " + this);
    }
}
     

Esto funciona bien, pero no se compilará sin la declaración de lanzamiento,   lo que no es terriblemente bonito. Peor aún, debes recordar agregar un nuevo   caso a la instrucción switch cada vez que agregue una nueva constante a   Operación. Si te olvidas, el método eval falla, ejecutando el   declaración de lanzamiento mencionada anteriormente

     

Hay otra manera de dar a cada constante de enumeración un comportamiento diferente para   Algún método que evita estos problemas. Puedes declarar el método.   Resumen en el tipo de enumeración y anularlo con un método concreto en   cada constante Tales métodos se conocen como métodos específicos de constantes.   Aquí está el ejemplo anterior rehecho usando esta técnica:

public enum Operation {
  PLUS   { double eval(double x, double y) { return x + y; } },
  MINUS  { double eval(double x, double y) { return x - y; } },
  TIMES  { double eval(double x, double y) { return x * y; } },
  DIVIDE { double eval(double x, double y) { return x / y; } };

  // Do arithmetic op represented by this constant
  abstract double eval(double x, double y);
}

Personalmente no me importa lanzar una excepción y manejar explícitamente todas las posibilidades, excepto si el cambio se ubicaría en la enumeración en sí. El IDE me da una advertencia (incluso puedo configurarlo para convertirlo en un error para que no se compile) cuando no maneja todos los casos. Si mantienes tus proyectos libres de advertencias, lo que trato de hacer, sabrás de manera inmediata qué archivos necesitan que se actualicen sus declaraciones de cambio.

    
respondido por el Darsstar 18.11.2015 - 16:19
-1

Sé que esto es antiguo y ya está respondido, pero otra opción sería el patrón de creación.

public enum A {
  A1(new EnumBuilder().set1(true).set2(true).set3(false)),
  A2(new EnumBuilder().set1(true).set2(false).set3(true)),
  A3(new EnumBuilder().set1(false).set2(false).set3(false));

private A(EnumBuilder builder){
    param1 = builder.param1;
    // etc.
}
...
}

class EnumBuilder {
    private boolean param1, param2, param3;

    EnumBuilder set1(boolean value){
        param1 = value;
        return this;
    }

    // etc.
}
    
respondido por el nasch 23.05.2018 - 23:06

Lea otras preguntas en las etiquetas