方便的方法来创建包装器

时间:2017-04-19 08:20:45

标签: java

问题

我需要对几种方法的结果反复执行逻辑。方法可以具有任意结果类型。简单的用例如下所示:

带有execute方法的包装类:

/**
 * Wrapper class which executes inner logic, processes the result of that logic and returns the processed result.
 *
 * @param <T>
 */
public abstract class Wrapper<T> {    
    /**
     * Perform inner logic
     */
    public abstract T run();

    /**
     * Invoke inner logic and process it.
     */
    public T execute() {            
        T result = run();           
        // TODO: process result         
        return result;
    }       
}

内部类中的逻辑,Wrapper的示例用法:

public class WrapperDemo {      
    /**
     * Simple invocation of the inner logic and then the outer logic
     */
    public static Boolean testMethod() {        
        // wrap around logic and execute
        return new Wrapper<Boolean>() {    
            @Override
            public Boolean run() {                  
                // TODO: perform logic, simply returning true for now 
                return Boolean.TRUE;
            }               
        }.execute();
    }

    public static void main(String[] args) {            
        // demo method invocation
        Boolean result = WrapperDemo.testMethod();          
        // process result
        System.out.println(result);         
        System.exit(0);         
    }       
}

我必须将其应用于几百种方法。

问题

有没有人知道使用testMethod(例如可能是注释)的代码更少的代码来更方便地编码?

3 个答案:

答案 0 :(得分:1)

如果你有Java 8,你可以写下以下内容:

public static <T> T execute(Wrapper<T> wrapper) {
  return wrapper.execute();
}

然后使用它如下:

public static Boolean testMethod() {
  return execute(()-> {
    return Boolean.TRUE;
  });
}

虽然我没有看到这比以下更好:

public static <T> T wrap(T result) {
  // Process result
  return result
}

并像这样使用它:

public static Boolean testMethod() {
  return wrap(Boolean.TRUE);
}

答案 1 :(得分:1)

在Java 8中,通过组合lambda和default方法,您可以在API中实现类似的功能而不需要进行太多更改(除了您需要使Wrapper成为接口而不是抽象类)

public interface Wrapper<T> {    
    public T run();

    default public T execute() {            
        T result = run();
        // TODO: process result
        return result;
    }
}

然后你可以通过

来调用它
public static Boolean testMethod() {
    Wrapper<Boolean> w = ()-> {return Boolean.TRUE;};
    return w.execute();
}

但就我个人而言,我认为它没有多大意义。

如果你想在逻辑上添加额外的逻辑,可能你需要的是一点点扭曲:

public class ExtraAction<T> {
    Supplier<T> supplier;
    public ExtraAction(Supplier<T> supplier) {
        this.supplier = supplier;
    }
    public T execute() {
        T result = this.supplier.get();
        // some extra processsing
        return result;
    }
}

所以它会被称为

Boolean result = new ExtraAction<>(()->{return Boolean.TRUE}).execute();

更好的是,在Wrapper Function<X,Y>中制作你的逻辑,然后组合起来将你的SupplierFunction组合在一起,这样看起来就像

result = Foo.forInput( ()-> { return logicToGetResult(); })
            .doExtra(ExtraAction::whateverAction).result();

答案 2 :(得分:1)

如果要使用注释,则应使用允许使用此类反射的工具。不能使用基本反射因为那样你就不能拦截&#34;电话。 Java的代理可能会有所帮助,但您已经限制使用接口,这并不总是人们想要的。

cglib是一个删除所有麻烦的库。有了它,您可以尝试以下方法:

@Target(METHOD)
@Retention(RUNTIME)
public @interface Wrap {
}

class Demo {
  @Wrap
  public Boolean testMethod() {
    return Boolean.TRUE;
  }
}

class Wrapper {
  public <T> T newInstance(Class<T> type) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(type);
    enhancer.setCallback(new InvocationHandler(){
      @Override public Object invoke(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        Object result = proxy.invokeSuper(obj, args);
        if (method.isAnnotationPresent(Wrap.class)) {
          execute(result);
        }
        return result;
      }
    });
    return enhancer.create();
  }

  public void execute(Object result) {
    // Add custom behavior to @Wrap-ped methods.
  }
}

然后你必须像这样调用包装器:

Demo demo = new Wrapper().newInstance(Demo.class);
demo.testMethod();

其他库也存在,如Byte Buddy或Javassist。但要小心,因为Java 9非常接近并迫使这些库非常快速地改变它们的核心业务,可能使它们不稳定。