最近,我正在与另一位程序员讨论重构充满“if”语句的巨大(1000行)方法的最佳方法。
该代码是用Java编写的,但是我想这个问题也可能在其他语言(例如C#)中发生。
为了解决此问题,他建议使用责任链模式。
他建议开设一个基本的“处理程序”类。然后,“Handler1”,“Handler2”等将扩展“Handler”。
然后,处理程序将具有“getSuccessor”方法,该方法将返回null(如果它是链的最后一个)或返回链的下一个Handler。
然后,“handleRequest(Request)”函数将处理Request或将其传递到链的下一个,如果先前的解决方案均不起作用,它将仅返回null或引发异常。
要向链中添加新的Handler,编码人员将转到链的最后一个元素,并告诉它有一个新元素。为了做某事,他只需要在链的第一个元素上调用handleRequest。
为了解决此问题,我建议使用其他方法。
我也会有一个基本的“Handler”类,分别带有“Handler1”,“Handler2”,就像前面提到的方法一样。
但是,将没有“getSuccessor”方法。相反,我有一个带有处理程序列表的Collection类(一个Vector,一个ArrayList或在这种情况下最好的任何东西)。
handleRequest函数仍然存在,但不会将调用传播到下一个处理程序。它只会处理请求或返回null。
要处理请求,可以使用
for(Handler handle : handlers){
result = handle.handleRequest(request);
if(result!=null) return result;
}
throw new CouldNotParseRequestException(); //just like in the other approach
或者,为防止代码重复,可以将“parseRequest(request)”方法添加到集合类中。
要添加一个新的处理程序,可以转到集合构造函数(或static {}块,或等价的东西),然后简单地添加代码“addHandler(new Handler3());”。
我确实缺少这种方法的责任链的哪些优势?哪种方法最好(假设有最好的方法)?为什么?每种设计方法可能导致哪些潜在的错误和问题?
对于那些需要上下文的人,原始代码如下所示:
if(x instanceof Type1)
{
//doSomething1
} else if(x instanceof Type2)
{
//doSomething2
}
//etc.
最佳答案
我比其他继任者更喜欢您的 Collection 理念。它使操作这组处理程序变得简单明了:collections接口(interface)是众所周知的,每个人都知道如何遍历List或不进行迭代。
如果您使用 friend 建议的这种后继方式,请注意不要陷入非常深层次的递归中(除非您的平台支持尾部调用,否则我不知道JVM是否能够做到这一点)。
我不建议向集合中添加任何方法。您将获得更加复杂的设计,难以理解和修改。有两个独立的问题:存储一组处理程序,并将此处理程序解释为责任链。通过对集合进行迭代来处理请求的方法比集合内务管理方法具有更高的抽象级别,因此不应属于集合接口(interface)。