在我们的系统中,我们有一个抽象类,我们称之为 BasicAction ,它包含几个抽象方法。其中最重要的是执行。它处理来自JSP页面的请求。主处理程序的工作方式如下:
// Sample 1:
String actionName;// The name of action to use
Map<String, BasicAction> mapping;//The mapping of names and actual handlers
BasicAction action = mapping.get(actionName);
try {
action.execute(request);//Handle the http request from the JSP page
} catch (Exception ex) {
// Handle here any exceptions
}
现在,一切看起来都很好,但基本上所有派生的处理程序都实现相同的代码:
// Sample 1:
public class ConcreteAction extends BasicAction {
@Override
public void execute(HttpServletRequest request) {
// The managers provide the middle layer between
// web presentation and database
TrafficManager trafficManager = null;
CargoManager cargoManager = null;
try {
trafficManager = new TrafficManager();
cargoManager = new CargoManager();
// Perform here all the logic required using managers
} catch (Exception ex) {
// handle the exception or rethrow it
} finally {
// Should remove all managers clearly and release the connection
removeManager(trafficManager);
removeManager(cargoManager);
}
}
}
在我拥有的每个处理程序中编写这样的块似乎有点烦人。似乎在这里我们模仿每个处理程序的输入/退出点而不是应该这样做。我认为我们需要的是在 BasicAction 中定义两个名为 createManagers 和 disposeManagers 的抽象方法。然后主处理程序将如下所示:
// Sample 2:
String actionName;// The name of action to use
Map<String, BasicAction> mapping;//The mapping of names and actual handlers
BasicAction action = mapping.get(actionName);
try {
action.createManagers(); // The enter point
action.execute(request);//Handle the http request from the JSP page
} catch (Exception ex) {
// Handle here any exceptions
} finally {
action.disposeManagers(); // The exit point
}
之后,每个派生动作处理程序都可以这样定义:
// Sample 2:
public class ConcreteAction extends BasicAction {
private TrafficManager trafficManager = null;
private CargoManager cargoManager = null;
@Override
public void createManagers() {
trafficManager = new TrafficManager();
cargoManager = new CargoManager();
}
@Override
public void disposeManagers() {
removeManager(trafficManager);
removeManager(cargoManager);
}
@Override
public void execute(HttpServletRequest request) {
// Perform here all the logic required using managers
}
}
最好使用哪种方法 - 在每个处理程序中使用try-catch-finally或使用标准的输入/退出点。
答案 0 :(得分:5)
就个人而言,我会选择抽象类方法,因为sounds like the Strategy pattern。而且,代码更清晰,更容易理解;加上 - 你不是一遍又一遍地重复这个结构。但这只是我的观点,有人可能会提出相反的建议。
答案 1 :(得分:1)
让createManagers()返回一个管理器列表。然后调用类可以在每个调用类上调用removeManager(),从而不需要disposeManagers()。
此外,您通过使用继承来结合BasicAction和ConcreteAction。这不是必需的。你可以通过构图将它们结合起来。如果ConcreteAction实现了IBasicAction接口,则单独的ActionRunner类可以对该操作调用createManagers()和execute()。您可以将ConcreteAction实例传递给ActionRunner。
答案 2 :(得分:0)
去抽象(选项2)。
应该抽象出通用代码,尤其是常见的处理流程。这使得子类可以自由地实现差异,并且意味着可以单独测试抽象代码 - 例如使用模拟/测试实现。
请注意,你可以采取这种方式,因此常识适用,但始终要留意抽象点。
答案 3 :(得分:0)
我通常使用后一种方法,因为它使重用更简单。通常,我需要为许多操作使用相同的管理器,因此我可以实现create / dispose代码一次,然后剩下的只是一个小execute()
方法。
如果这种方法不起作用,我仍然可以覆盖原始的处理程序方法,因此我可以充分利用这两种方法。
答案 4 :(得分:0)
抽象类将提供保证 of of sort 以便始终调用清理代码,并且它减少了重复,因此在我看来它比现有结构更好。当然,您无法知道子类的disposeManagers
实现会完全杀死它之前创建的那些管理器 - 但是编写标准finally
块时也存在同样的问题。
我想我会更进一步。首先,execute
方法需要这两位经理来完成工作,所以我将其定义为
public void execute(HttpServletRequest req, TrafficManager t, CargoManager c);
现在让我们假设您的大多数操作都使用相同的管理器实现。我们在超类中定义了这些方法(尽管不是最终的):
public TrafficManager createTrafficManager() { return new TrafficManager(); }
public CargoManager createCargoManager() { return new CargoManager(); }
所以现在超类可以通过调用方法自己创建这些实例,并将它们传递给execute。如果子类需要与默认值不同的实现,它可以按需要覆盖该方法。
查看清理 - 我们可以采用与上述类似的方法并定义抽象实现。但是,如果管理员需要进行清理,那么他们可能会实施close()
方法或类似方法。在这种情况下,我们可以调用它 - 这可以保证它们将被正确处理,而不管子类的实现如何,并且try
和finally
不可能不同步。 / p>
或者您可以在每个上面调用removeManager
,如果这是您的逻辑需要的话。 (这可能会进一步改进,但它取决于该方法的语义,以及它“活着”的位置。)
然后,BasicAction的主要代码看起来像
BasicAction action = mapping.get(actionName);
// (It's a shame that these need the initial assignment to null due to being
// referenced in the finally block - it's pretty ugly)
TrafficManager tMan = null;
CargoManager cMan = null;
try {
tMan = createTrafficManager();
cMan = createCargoManager();
action.execute(request, tMan, cMan);//Handle the http request from the JSP page
} catch (Exception ex) {
// Handle here any exceptions
} finally {
if (tMan != null) {
removeManager(tMan); // Is this necessary, did it get registered somewhere after creation?
tMan.close(); // If they're closeable
}
if (cMan != null) {
// Of course this block could be a tiny method to further remove duplication,
// so long as you have a common superinterface for both *Manager classes
removeManager(cMan);
cMan.close();
}
}