我正在寻找一种设计模式来处理作为方法参数接收的Exception
个实例。
为了在问题中添加一些上下文,我使用GWT并拥有各种异步处理程序,通常采用类似于以下的形式:
public interface AsyncCallback<T> {
void onFailure(Throwable caught);
void onSuccess(T result);
}
因此,onFailure
方法会收到我需要处理的Throwable
实例。
现在,我在此方法中可以收到许多例外情况,例如
ConstraintViolationException
TimeoutException
NoSuchElementException
在我的处理代码中,我当然可以写下以下内容:
void handleException(final Exception e) {
if(e instanceof TimeoutException) {
handleTimeout();
} else if (e instanceof NoSuchElementException) {
handleInvalidElement();
} else {
stopAndCatchFire();
}
}
但在我看来,这看起来非常难看。大if..else if
链与instanceof
的大量使用相结合似乎是应该避免的。
我想也许我可以使用try...catch
构造来处理Exception
,使用类似下面的内容:
void handleException(final Exception e) {
try {
throw e;
} catch (TimeoutException te) {
handleTimeout();
} catch (NoSuchElementException nsee) {
handleInvalidElement();
} catch (Exception ex) {
stopAndCatchFire();
}
}
但这似乎是一种虐待。您是否认为第二种方法有任何缺点,或者我可以采用另一种方法来避免第一种情况?
答案 0 :(得分:3)
你能否拥有一个由他们处理的异常类型键入的exceptionHandlers字典,然后当你得到一个异常时,你会在字典中查找异常类型的处理程序。如果有,则将异常传递给处理程序,如果没有则使用默认处理程序。
所以你的处理程序就像这样:
void handleException(final Exception e) {
if (handlers.containsKey(e.getType())
{
handlers[e.getType()].handle(e);
}
else
{
defaultHandler.handle(e);
}
}
我的Java有点生疏,所以这个例子很简单,但应该很容易翻译(虽然我记得没有把所有内容的第一个字母大写:))
这种方法的优点是可以简单地添加新的处理程序。
如果您对子类型具有相同的处理程序,则会受到影响,因为您必须明确注册每个子类型。
要解决此问题,只需让每个处理程序负责决定是否可以处理异常:
public interface ExceptionHandler
{
bool canHandle(Exception e);
void handle(Exception e)
}
然后只需将处理程序放在一个迭代列表中,询问每个处理程序是否可以处理当前异常,当你找到一个可以处理它时,让它处理它。
答案 1 :(得分:1)
但在我看来,这看起来非常难看。大量的if..else if链与大量使用instanceof相结合似乎是应该避免的。
我不同意。我认为这段代码正好使用了两种语言结构。如果代码变得难以管理(太多条款),那么您应该一般地质疑错误处理的方法,而不是这个方法的细节。在那个阶段你可能想要考虑AOP。
另一方面,第二种方法很可怕;)
答案 2 :(得分:1)
只需处理函数内异常中的if语句,就可以使它更优雅。
void handleException(Exception e){
handleOne(e)
handleTwo(e)
...
}
它看起来更漂亮。当然,每个函数总是被调用,但它的第一行只是一个if语句。有变化 - 例如使你的句柄函数guava函数对象,将它们放在一个列表中,并迭代它们,直到你得到第一个返回“true”。类似的东西:
public class handlerOne implements Function<Exception, Boolean> {
Boolean apply(Exception input) {
return handlerOne();
}
}
然后你的句柄功能可以是:
void handleException(Exception e){
list<Function<Exception, Boolean> list = Object.getHandlers(); //store your handlers somewhere
for(Function<Exception, Boolean> f : list){
if(f.apply(e)){
break
}
}
}
这样你就可以确保只调用一个有效的处理程序,你可以通过改变列表的顺序来控制顺序,因为列表迭代器会按顺序返回它们。
答案 3 :(得分:0)
应避免对异常进行控制流程,并且当然不应该在onFailure中。 onFailure方法应该尽可能简单。
修改异步运行的任何代码以处理那里的异常情况。可以通过在执行任何操作之前检查元素是否存在来处理ElementNotFound异常。超时异常可以通过try ... catch块包围可以超时(调用web服务或其他东西)的代码来处理。 然后扩展结果类型T以包含发生超时或找不到元素的额外信息 - 如果需要。