3

在我们的系统中,我们有一个抽象类,我们称之为BasicAction,它包含几个抽象方法。其中最重要的称为execute。它处理来自 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中定义另外两个抽象方法,称为createManagersdisposeManagers。然后主处理程序将如下所示:

// 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 或使用标准进入/退出点。

4

5 回答 5

5

就个人而言,我会选择抽象类方法,因为它听起来像 Strategy 模式。此外,代码更简洁,更易于理解;加 - 你不是一遍又一遍地重复结构。但这只是我的意见,有人可能会建议另一种方式。

于 2011-07-07T10:06:56.873 回答
1

让 createManagers() 返回一个管理器列表。然后调用类可以对每个类调用 removeManager(),从而不需要 disposeManagers()。

此外,您可以使用继承来耦合 BasicAction 和 ConcreteAction。这不是必需的。您可以改为通过组合来耦合它们。如果 ConcreteAction 实现了 IBasicAction 接口,则单独的类 ActionRunner 可以在操作上调用 createManagers() 和 execute()。您可以将 ConcreteAction 实例传递给 ActionRunner。

于 2011-07-07T10:10:26.377 回答
0

去抽象(选项2)。

通用代码,尤其是通用处理流程,应该抽象出来。这使得子类可以自由地实现差异,并意味着可以单独测试抽象代码 - 例如使用模拟/测试实现。

请注意,您可能会走得太远,因此常识适用,但请始终注意抽象点。

于 2011-07-07T10:06:41.623 回答
0

我通常使用后一种方法,因为它使重用更加简单。通常,我需要相同的管理器来执行许多操作,因此我可以实现一次创建/处置代码,然后剩下的就是一个小execute()方法。

如果这种方法不起作用,我仍然可以覆盖原始处理程序方法,因此我可以两全其美。

于 2011-07-07T10:07:11.990 回答
0

抽象类将提供某种保证即始终调用清理代码,并减少重复,因此在我看来它比您现有的结构更好。当然,您无法知道子类的实现会完全杀死它之前创建的那些管理器——但是您在编写标准块时disposeManagers也会遇到同样的问题。finally

我想我会更进一步。一方面,该execute方法需要这两个经理来完成工作,所以我将其定义为

public void execute(HttpServletRequest req, TrafficManager t, CargoManager c);

现在让我们假设您的大多数操作都使用相同的管理器实现。我们在超类中定义这些方法(虽然没有使它们成为最终方法):

public TrafficManager createTrafficManager() { return new TrafficManager(); }
public CargoManager createCargoManager() { return new CargoManager(); }

所以现在超类可以通过调用方法自己创建这些实例,并将它们传递给执行。如果子类需要与默认不同的实现,它可以根据需要覆盖该方法。

查看清理 - 我们可以采用与上述类似的方法并定义抽象实现。但是,如果需要清理管理器,那么大概他们实现了一种close()方法或类似的方法。try在这种情况下,我们可以直接调用它 - 这保证了它们将被正确处理,而不管子类的实现如何,并且and不可能不finally同步。

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();
  }
}
于 2011-07-07T10:13:53.743 回答