使用反射或面向方面编程?

时间:2012-09-29 14:47:56

标签: java

我在java中开发了一个包含大约30个操作的Web服务。除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. 我应该使用普通的旧开关案例语句和一种方法来根据操作决定调用哪种方法?

3 个答案:

答案 0 :(得分:8)

这看起来像template method pattern的好候选人。定义一个包含main方法(final)的抽象类,它将特定部分委托给受保护的抽象方法。

在Web服务的每个方法中,实例化此抽象类的子类,该子类仅覆盖两个特定的抽象方法,并调用此子类实例的main方法。

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();
    }

答案 1 :(得分:4)

模板方法/策略模式

每个方法都创建自己的Callable实例,并将其传递给一个通用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有lambdas,那么读写会更容易。

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 block can be placed in AfterThrowing and之后的建议。

答案 2 :(得分:0)

在这种情况下,您只需使用私有方法提取代码即可。

1。)反思将使它变得更慢,更难以理解和维护。

2。)当一个问题横切另一个问题时,应该使用AO技术。这不是真的,因为initializecallMethod1是整个算法的一部分,不能单独使用。

3。)开关语句是正确的思维方式,但却是“多态性”的标志。

你可以这样做:

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,并且您当然可以使用泛型来更改结果和异常类型。