3

約 30 の操作を含む Web サービスを Java で開発しました。各操作には、2 ~ 3 行を除いてまったく同じコードがあります。以下はコードのスケッチです

public Response operation1(String arg1, String arg2)
{
   initialze(); // this line will be different for each operation with different arguments
   authorizeSession();
   Response res;

   if (authorized)
   {
       try 
       {
          Object result = callMethod1(arg1, arg2); // This line is different for each operation
          res = Response.ok(result).build();
       }
       catch( MultipleExceptions ex)
       {
          res = handleExceptions();
       }
       finally
       {
           logInDatabase();
       }

   }
   return res;
}

各操作で同じコードを記述する必要がないようにするには、どのアプローチに従う必要がありますか?

  1. リフレクションを使用する必要がありますか?
  2. アスペクト指向プログラミングについて聞いたことがありますが、ここで AOP を使用できますか?
  3. 従来の switch case ステートメントと、操作に基づいて呼び出すメソッドを決定するメソッドを使用する必要がありますか?
4

3 に答える 3

11

これは、テンプレート メソッド patternの良い候補のようです。特定の部分を保護された抽象メソッドに委譲するメイン メソッド (最終) を含む抽象クラスを定義します。

Web サービスの各メソッドで、2 つの特定の抽象メソッドのみをオーバーライドするこの抽象クラスのサブクラスをインスタンス化し、このサブクラス インスタンスのメイン メソッドを呼び出します。

public abstract class Operation {
    public final Response answer(String arg1, String arg2) {
        authorizeSession();
        Response res;

        if (authorized) {
            try {
                Object result = executeSpecificPart(arg1, arg2);
                res = Response.ok(result).build();
            }
            catch (MultipleExceptions ex) {
                res = handleExceptions();
            }
            finally {
                logInDatabase();
            }
        }

        return res;
    }

    protected abstract Object executeSpecificPart(String arg1, String arg2);
}

...

    public Response operation1(final String arg1, final String arg2) {
        initialize();
        Operation op1 = new Operation() {
            protected Object executeSpecificPart(String arg1, String arg2) {
                ...
            }
        };
        return op1.answer();
    }
于 2012-09-29T14:55:52.757 に答える
5

テンプレート メソッド パターンおよび/または戦略パターン

各メソッドは独自のCallableインスタンスを作成し、それを 1 つの汎用run()メソッドに渡します。

public Response operation1(String arg1, String arg2)
{
    initialze(); // this line will be different for each operation with different arguments
    return run(new Callable<Object> {
        public Object call() {
            return callMethod1(arg1, arg2); // This line is different for each operation
        }
    });
}

private Response run(Callable<Object> method) {
   authorizeSession();
   if (authorized)
   {
       try 
       {
          Object result = method.call();
          return Response.ok(result).build();
       }
       catch( MultipleExceptions ex)
       {
          return handleExceptions();
       }
       finally
       {
           logInDatabase();
       }
   }
   return null;
}

Java にラムダがあれば、読み書きがはるかに簡単だったでしょう。

AOP

メソッドで何かをインターセプトする必要があるため、アスペクト指向プログラミングはここでは最適なツールではありません。AOP は、メソッドの前または後に何かを呼び出す必要がある場合 (またはメソッドが何かをスローする場合) に最適です。同じことが反射にも当てはまります。

ただし、AOP はエラー処理を大幅に改善します。コードは次のように縮小できます。

public Response operation1(String arg1, String arg2)
    {
    initialze(); // this line will be different for each operation with different arguments
    authorizeSession();

    if (authorized)
    {
        Object result = callMethod1(arg1, arg2); // This line is different for each operation
        return Response.ok(result).build();
    }
    return null;
    }

キャッチMultipleExceptionsfinallyブロックを入れAfterThrowingたりAfterアドバイスしたりできます。

于 2012-09-29T14:56:23.140 に答える
1

この場合、プライベート メソッドでコードを抽出するだけです。

1.) リフレクションにより、理解と維持が非常に遅くなり、難しくなります。

2.) ある懸念事項が別の懸念事項をクロスカットする場合、AO 手法を使用する必要があります。initializecallMethod1はアルゴリズム全体の一部であり、単独では機能しないため、これは実際には当てはまりません。

3.) switch ステートメントは正しい考え方ですが、「ポリモーフィズム恐怖症」の兆候です。

これはあなたがそれを行う方法です:

private static interface CallMethodHelper {
    Object callMethod() throws MultipleExceptions;
}

public Response operation1(final String arg1, final String arg2) {
    initialze(); 
    return operationHelper(new CallMethodHelper() {
        @Override
        public Object callMethod() throws MultipleExceptions {
            return callMethod1(arg1, arg2);
        }
    });
}

private Response operationHelper(CallMethodHelper helper) {
    authorizeSession();
    Response res = null;

    if (authorized) {
        try {
            Object result = helper.callMethod();
            res = Response.ok(result).build();
        } catch (MultipleExceptions ex) {
            res = handleExceptions();
        } finally {
            logInDatabase();
        }

    }
    return res;
}

引数を final にする必要があることに注意してください。もちろん、ジェネリックを使用して結果と例外の型を変更できます。

于 2012-09-29T14:52:48.763 に答える