try-catch-finally vs抽象方法

时间:2011-07-07 10:02:34

标签: java try-catch-finally

在我们的系统中,我们有一个抽象类,我们称之为 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或使用标准的输入/退出点。

5 个答案:

答案 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()方法或类似方法。在这种情况下,我们可以调用它 - 这可以保证它们将被正确处理,而不管子类的实现如何,并且tryfinally不可能不同步。 / 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();
  }
}