创建包装纸的方便方法



问题

我需要一遍又一遍地对几种方法的结果进行逻辑。这些方法可以具有任意结果类型。简单的用例看起来像这样:

带有执行方法的包装类别:

/**
 * 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;
    }       
}

和内部类中的逻辑,包装器的示例用法:

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

我必须将其应用于几种100秒的方法。

问题

有人知道一种更方便的方法来用更少的 testMethod代码编码此编码(例如,注释(?

如果您有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);
}

如果要使用注释,则应使用允许使用这种反射的工具。无法使用基本反射,因为您不能"拦截"调用。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();

其他库也存在,例如字节好友或Javassist。但是要小心,因为Java 9非常接近,并迫使这些图书馆非常非常快速地更改其核心业务,可能会使它们不稳定。

在java 8中,通过lambda和默认方法的组合,您可以实现类似的事情而无需更改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 A Function<X,Y>中,然后弥补您的SupplierFunction的链接,因此看起来像

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

相关内容

最新更新