2010-02-16 12 views
18

tengo este código:Cómo evitar la duplicación de complicados bloques catch

try { 
    do_stuff(); 
    return do_more_stuff(); 
} catch (UnsupportedEncodingException e) { 
    throw CustomException.programmer_error(e); 
} catch (ProtocolException e) { 
    throw CustomException.programmer_error(e); 
} catch (MalformedURLException e) { 
    throw CustomException.programmer_error(e); 
} catch (SocketTimeoutException e) { 
    throw new CustomException(e); 
} catch (IOException e) { 
    throw CustomException.unexpected_error(e); 
} 

ahora necesita tener todos esos bloques de captura en otra función similar. ¿Cuál es la mejor manera de evitar la duplicación aquí?

Tenga en cuenta que el código dentro de los dos bloques de prueba no es muy similar.

También realmente no puedo poner el conjunto de las capturas más arriba.

Nota, yo preferiría evitar:

try { 
    do_stuff(); 
    return do_more_stuff(); 
} catch (Exception e) { 
    handle_exception_via_rtti(e); 
} 
+0

¿por qué quieres evitar la versión rtti? – clamp

+0

Como dpb dice "Si su código simplemente detecta Excepción, y do_stuff y do_more_stuff luego agregan excepciones comprobadas adicionales, probablemente nunca sabrá sobre el cambio y el hecho de que su código podría estar equivocado". – mxcl

+1

Personalmente, me gustaría que tu método arrojara las excepciones originales. No hace mucho con sus bloques catch para 'manejar' nada excepto envolver en una CustomException. ¿Qué valor tiene esa suma? – duffymo

Respuesta

7

personal que iba a tratar de hacer la parte

do_stuff(); 
return do_more_stuff(); 

se ajustan a un formato más general con el fin de aplicar la estrategia (como un patrón).

Luego puede refactorizar todos los lugares donde llama a este tipo de bloque para que puedan llamar a un bloque más generalizado (donde las capturas se distribuyen solo una vez).

+2

De hecho, el patrón de estrategia funcionará aquí. Para las generaciones futuras, esto implicaría reemplazar 'do_stuff(); devuelve do_more_stuff() 'con' return strategy.do_stuff() '. Por lo tanto, pasa la estrategia a su función de controlador de excepción. Este patrón requeriría que todas las estrategias devuelvan el mismo tipo de do_stuff(); – mxcl

5

Nota, preferiría evitar:

Entonces, o simplemente vivir con ella, o esperar hasta JDK7 viene con Multicatch para que pueda reescribir como:

try { 
    do_stuff(); 
    return do_more_stuff(); 
} catch (UnsupportedEncodingException | ProtocolException | MalformedURLException e) { 
    throw CustomException.programmer_error(e); 
} catch (SocketTimeoutException e) { 
    throw new CustomException(e); 
} catch (IOException e) { 
    throw CustomException.unexpected_error(e); 
} 

Alternativamente, también puede mover esto al constructor de CustomException y realizar una captura global (desagradable), pero luego deberá agregar un grupo de (desagradables) if/else bloques para determinar el tipo de causa de la excepción. Con todo, preferiría seguir el camino como ya lo hiciste.

actualización: otra alternativa es dividir/refactorizar las líneas de lo que potencialmente puede lanzar la excepción como tareas separadas en otros bloques del método de lanzamiento CustomException. P.ej.

try { 
    do_stuff_with_encoding(); 
    do_stuff_with_url(); 
    do_stuff_with_ws(); 
    // ... 
    return do_more_stuff(); 
} catch (SocketTimeoutException e) { 
    throw new CustomException(e); 
} catch (IOException e) { 
    throw CustomException.unexpected_error(e); 
} 

... 

public SomeObject do_stuff_with_encoding() throws CustomException { 
    try { 
     do_stuff(); 
    } catch (UnsupportedEncodingException e) { 
     throw CustomException.programmer_error(e); 
    } 
} 

public SomeObject do_stuff_with_url() throws CustomException { 
    try { 
     do_stuff(); 
    } catch (MalformedURLException e) { 
     throw CustomException.programmer_error(e); 
    } 
} 

public SomeObject do_stuff_with_ws() throws CustomException { 
    try { 
     do_stuff(); 
    } catch (ProtocolException e) { 
     throw CustomException.programmer_error(e); 
    } 
} 
+1

@BalusC: Desafortunadamente, esa propuesta fue rechazada: http://blogs.sun.com/darcy/entry/project_coin_final_five (a menos que alguien aquí pueda corregirme sobre esto ...) – Tim

+1

@Tim: ahora se está reconsiderando la inclusión de http: //blogs.sun.com/darcy/entry/projec_coin_post_devoxx_closures –

+0

@Ben: ¡Gracias! No lo sabía. Esperemos que lo incluyan después de todo .. – Tim

2

Depende de por qué el do_stuff y do_more_stuff arrojan las excepciones marcadas. ¿Están haciendo eso para obligar al usuario a tratar la excepción? Si es así, entonces intenta evitar:

try { 
    do_stuff(); 
    return do_more_stuff(); 
} catch (Exception e) { 
    handle_exception_via_rtti(e); 
} 

es una buena cosa.

Si su código sólo atrapa Exception y el do_stuff y do_more_stuff más adelante agregar excepciones adicionales, es probable que nunca se sabe sobre el cambio y el hecho de que el código de ahora podría estar equivocado.

Por lo que es posible que tenga que tratar con throwing the kitchen sink y trate todas esas excepciones, a menos que los métodos puedan cambiar a excepciones no verificadas.

Por otro lado, si los métodos arrojan excepciones comprobadas solo porque el programador era flojo al tratar con ellos y solo quería pasar el dinero, tal vez está mirando esto desde el ángulo equivocado.

+0

Gracias su comentario realmente me ayudó a evaluar cómo me estaba acercando al problema. De hecho, evito tirar el fregadero de la cocina, y no estoy pasando el dinero. – mxcl

1

¿Qué hay de introducir una clase de acción genérico que puede tener subclases:

public class Action { 
    public void runWithHandlers() throws Exception { 
     try { 
      run(); 
     } catch (UnsupportedEncodingException e) { 
      throw CustomException.programmer_error(e); 
     } catch (ProtocolException e) { 
      throw CustomException.programmer_error(e); 
     } catch (MalformedURLException e) { 
      throw CustomException.programmer_error(e); 
     } catch (SocketTimeoutException e) { 
      throw new CustomException(e); 
     } catch (IOException e) { 
      throw CustomException.unexpected_error(e); 
     } 
    } 
    public void run() throws Exception { 
     // TODO subclasses of Action must implement this 
    } 
} 

A continuación, en otra parte de su código se instancia una de las subclases de Acción y llaman runWithHandlers():

new MyAction().runWithHandlers(); 
+0

Buena respuesta. Pero se lo daré al tipo que sugirió el patrón de Estrategia, creo. Esto es similar y, francamente, lo prefiero (es más simple), pero creo que es sensato dirigir a otras personas hacia algo más fácilmente nombrado. – mxcl

+0

Mi solución tiene un nombre en realidad: es el patrón de método de plantilla bien conocido, directamente del libro de GoF :-) –

Cuestiones relacionadas