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という2つの抽象メソッドを定義することだと思います。その場合、メインハンドラーは次のようになります。

// 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

個人的には、ストラテジーパターンのように聞こえるので、抽象クラスアプローチを採用します。さらに、コードはよりクリーンでわかりやすくなっています。プラス-構造を何度も繰り返さない。しかし、それは私の意見にすぎません。誰かが別の方法を提案するかもしれません。

于 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メソッドはそれらの2人のマネージャーが作業を行う必要があるので、私はそれを次のように定義します。

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

ここで、ほとんどのアクションが同じマネージャー実装を使用していると仮定しましょう。これらのメソッドをスーパークラスで定義します(ただし、最終的なものにはしません)。

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

これで、スーパークラスはメソッドを呼び出してこれらのインスタンス自体を作成し、それらを実行に渡すことができます。また、サブクラスにデフォルトとは異なる実装が必要な場合は、必要に応じてメソッドをオーバーライドできます。

クリーンアップを見ると、上記と同様のアプローチを取り、抽象的な実装を定義できます。ただし、管理者をクリーンアップする必要close()がある場合は、おそらく、管理者はメソッドなどを実装します。その場合、それを呼び出すことができます-これは、サブクラスの実装に関係なく、それらが適切に破棄されることを保証し、とが同期しなくなることはtryありません。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 に答える