2010-10-22 13 views
7

tengo enumeración decir que ErrorCodes"if" vs Diseño OO

public enum ErrorCodes { 
     INVALID_LOGIN(100), 
     INVALID_PASSWORD(101), 
     SESSION_EXPIRED(102) ...; 

     private int errorCode; 

     private ErrorCodes(int error){ 
       this.errorCode = error; 
     } //setter and getter and other codes 
} 

ahora verifico mis códigos de error de excepción con este código de error. No quiero escribir si esto hace esto, si esto hace esto. Cómo puedo resolver este problema (escribiendo 10+ si se bloquean)

¿Existe algún patrón de diseño para esa situación?

Gracias

+0

¿Está ayudando con la declaración del caso o me falta algo? – Jean

+0

Sí, ya que de esta manera tendría que cambiar su implementación cada vez que cambie la enumeración (por ejemplo, nuevas declaraciones de casos). Cuando implemente su código basado en un buen diseño de OO, intente abrir extensiones pero cierre para modificaciones. – Mephisztoe

Respuesta

3

Como lo señaló Spoike, usar polimorfismo para elegir el método correcto de manejo de errores es una opción. Este enfoque básicamente difiere los 10+ si bloquea la búsqueda de métodos virtuales de la JVM, al definir una jerarquía de clases.

Pero antes de ir a una jerarquía de clases en toda regla, también considere usar los métodos enum. Esta opción funciona bien si lo que planea hacer en cada caso es bastante similar.

Por ejemplo, si desea devolver un mensaje de error diferente para cada ErrorCode, puede simplemente hacer esto:

// Note singular name for enum 
public enum ErrorCode { 
    INVALID_LOGIN(100, "Your login is invalid"), 
    INVALID_PASSWORD(101, "Your password is invalid"), 
    SESSION_EXPIRED(102, "Your session has expired"); 

    private final int code; 
    private final String 

    private ErrorCode(int code, String message){ 
      this.code = code; 
      this.message = message; 
    } 

    public String getMessage() { 
     return message; 
    } 
} 

A continuación, el código de control de errores se convierte simplemente:

ErrorCode errorCode = getErrorCode(); 
prompt(errorCode.getMessage()); 

Una desventaja de este enfoque es que si desea agregar casos adicionales, deberá modificar la enumeración en sí, mientras que con una jerarquía de clases puede agregar casos nuevos sin modificar el código existente.

+0

Gracias He resuelto mi problema simplemente agregando este método: public static String getErrorMessage (int errorCode); y encuentre el mensaje en ErrorCode.values. ¡Gracias por todo! –

+0

Bueno para escuchar :) – oksayt

+0

Por cierto, si actualmente está recorriendo todos los elementos ErrorCode.values ​​en cada búsqueda de código de error, eche un vistazo a esta solución que puede hacerlo en tiempo constante: http://stackoverflow.com/questions/ 2780129/get-enum-by-its-inner-field/2780170 # 2780170 – oksayt

2

creo que lo mejor que puede hacer es implementar el patrón de estrategia. De esta forma, no tendrá que cambiar las clases existentes al agregar nuevas enumeraciones, pero podrá ampliarlas. (Principio abierto-cerrado).

Búsqueda de patrón de estrategia y principio abierto cerrado.

0

Se puede crear un mapa de códigos de error (entero) en contra de tipos de enumeración

Editar

En esta solución, una vez que el mapa se prepara, puede buscar un código de error en el mapa y por lo tanto, no se requerirá si ... mira hacia arriba.

E.g.

Map<Integer, ErrorCodes> errorMap = new HashMap<Integer, ErrorCodes>(); 
for (ErrorCodes error : ErrorCodes.values()) { 
    errorMap.put(error.getCode(), error); 
} 

Ahora, cuando usted quiere comprobar un código de error que proviene de la aplpication, todo lo que tiene que hacer es,

ErrorCodes error = errorMap.get(erro_code_from_application); 

eliminando así la necesidad de que todo el if..else.

Solo tiene que configurar el mapa de forma tal que la adición de códigos de error no requiera cambios en otros códigos. La preparación del mapa es una actividad única y se puede vincular a una base de datos, un archivo de propiedades, etc. durante la inicialización de su aplicación

+0

Supongo que esta no es la solución. Mi código está en este momento pero no obedece a los principios. Quiero decir, escribir declaraciones if: if() else if() else if() .... else() no es una buena solución –

7

O lo hace con un comando if o un interruptor, o simplemente implementa la lógica en cuestión en el ErrorCode de alguna manera.

De manera OO, todo depende de cómo quiera que la aplicación o el sistema reaccionen al código de error. Digamos que sólo quiere que somekind salida del diálogo:

public doSomethingWithError() { 

    ErrorCodes e = getError(); 
    // the source of error, or originator, returns the enum 

    switch(e) { 
    case ErrorCodes.INVALID_LOGIN: 
     prompt('Invalid Login'); 
    case ErrorCodes.INVALID_PASSWORD: 
     prompt('Invalid password'); 
    // and so on 
    } 

} 

Podríamos lugar crear una clase ManejadorError que hace esto en su lugar:

// We'll implement this using OO instead 
public doSomethingWithError() { 

    ErrorHandler e = getError(); 
    // the originator now returns an ErrorHandler object instead 

    e.handleMessage(); 

} 

// We will need the following abstract class: 
public abstract class ErrorHandler { 

    // Lets say we have a prompter class that prompts the message 
    private Prompter prompter = new Prompter(); 

    public final void handleMessage() { 
    String message = this.getMessage(); 
    prompter.prompt(message); 
    } 

    // This needs to be implemented in subclasses because 
    // handleMessage() method is using it. 
    public abstract String getMessage(); 
} 

// And you'll have the following implementations, e.g. 
// for invalid logins: 
public final class InvalidLoginHandler() { 

    public final String getMessage() { 
    return "Invalid login"; 
    } 

} 

// E.g. for invalid password: 
public final class InvalidPasswordHandler() { 
    public final String getMessage() { 
    return "Invalid password"; 
    } 
} 

La primera solución es fácil de implementar, pero se hace difícil mantener a medida que el código crece. La última solución es más compleja (Template Method pattern) después del Open-Closed Principle pero le permite agregar más métodos al ErrorHandler cuando lo necesite (como restaurar recursos o lo que sea). También puede implementar esto con el Strategy pattern.

No se saldrá completamente con los enunciados condicionales, pero en este último el condicional se inserta en la parte del código donde se originó el error. De esta forma, no tendrá doble mantenimiento en los enunciados condicionales tanto en el originador como en el código de manejo de errores.

EDIT:

Ver this answer by Michael Borgwardt y this answer by oksayt de cómo poner en práctica los métodos de enumeraciones de Java si desea hacerlo en su lugar.

0

En mi opinión, no hay nada de malo con ErrorCodes como enums y una instrucción switch para despachar el manejo de errores. Los mensajes y el interruptor encajan muy bien.

Sin embargo, tal vez encuentre el siguiente insteresting (tipo de sobrediseño), vea an Example o "Double dispatching" on Wikipedia. requisitos asumidas:

  • de manejo de errores debe ser encapsulada en una clase propia
  • de manejo de errores debe ser reemplazable
  • seguridad
  • Tipo: Cada vez que se añade un error, que se ven obligados a añadir gestión de errores en cada implementación de controlador de errores. No es posible "olvidar" un error en uno (de tal vez muchos) cambios en los estatutos.

el código:

//Inteface for type-safe error handler 
interface ErrorHandler { 
    void handleInvalidLoginError(InvalidLoginError error); 
    void handleInvalidPasswordError(InvalidLoginError error); 
//One method must be added for each kind error. No chance to "forget" one. 
} 

//The error hierachy 
public class AbstractError(Exception) { 
    private int code; 
    abstract public void handle(ErrorHandler); 
} 
public class InvalidLoginError(AbstractError) { 
    private String additionalStuff; 
    public void handle(ErrorHandler handler) { 
     handler.handleInvalidLoginError(this); 
    } 
    public String getAdditionalStuff(); 
} 
public class InvalidPasswordError(AbstractError) { 
    private int code; 
    public void handle(ErrorHandler handler) { 
     handler.handleInvalidPasswordError(this); 
    } 
} 

//Test class 
public class Test { 
    public void test() { 
     //Create an error handler instance. 
     ErrorHandler handler = new LoggingErrorHandler(); 

     try { 
      doSomething();//throws AbstractError 
     } 
     catch (AbstractError e) { 
      e.handle(handler); 
     } 
    } 
} 
4

enumeraciones de Java son muy potentes y permiten implementaciones de métodos por instancia:

public enum ErrorCode { 
     INVALID_LOGIN { 
     public void handleError() { 
      // do something 
     } 
    }, 
     INVALID_PASSWORD { 
     public void handleError() { 
      // do something else 
     } 
    }, 
     SESSION_EXPIRED { 
     public void handleError() { 
      // do something else again 
     } 
    }; 

    public abstract void handleError(); 
} 

A continuación, sólo tiene que llamar errorCode.handleError();. Sin embargo, es cuestionable si una enumeración ErrorCode es realmente el lugar correcto para esa lógica.

+1

Ah, no me di cuenta de que podría agregar métodos abstractos en una enumeración. Bastante inteligente. – Spoike

+0

Gracias de antemano. Creo que para implementar una interfaz que amplíe otra interfaz que tenga demasiados códigos. Borro todo. Este enfoque es muy atractivo –