包装器提供统一的方法参数

时间:2017-07-13 07:22:01

标签: java

在Python中,我可以这样做:

class Demo:
    def x(self, prefix, x, y):
        print("Demo.x, prefix=%s, x=%s, y=%s" % (prefix, x, y))
        return 3

    def y(self, prefix, i):
        print("Demo.y, prefix=%s, i=%d" % (prefix, i))

class Wrapper:
    def __init__(self, inst, prefix):
        self.inst = inst
        self.prefix = prefix

    def __getattr__(self, name):
        print("function %s is called" % name)
        func = getattr(self.inst, name)
        return lambda *args, **kwargs: func(self.prefix, *args, **kwargs)

if __name__ == "__main__":
    inst = Demo()
    wrapper = Wrapper(inst, "prefix")
    print(wrapper.x("a", "b")) 
    wrapper.y(123)

在这段代码中我可以使用包装器来提供统一的前缀,而无需在类Wrapper中重新定义类Demo的所有方法。

我只是想知道如何在Java中实现相同的东西?

我看了动态代理,但似乎无法改变论点。

这是我试过的:

public class Wrapper {

  private Class cls;
  private final Object inst;
  private final String header;

  public Wrapper(Class cls, Object inst, String header){
    System.out.println("C=" + cls.getName());
    this.cls = cls;
    this.inst = inst;
    this.header = header;
  }

  public Object invoke(String funcName, Object ...args)
      throws InvocationTargetException, IllegalAccessException {

    for (Method method : this.cls.getMethods()) {
      if (method.getName().equals(funcName)) {
        ArrayList argList = new ArrayList(Arrays.asList(args));
        argList.add(0, header);
        return method.invoke(this.inst, argList.toArray());
      }
    }
    return null;
  }
}

可以用作:

Wrapper wrapper = new Wrapper(DemoService.class, service, "prefix");
return (String)wrapper.invoke("test", "this is a test");

然而,"调用"方法不是那么直观和方便。

1 个答案:

答案 0 :(得分:0)

实现所需包装器功能的一种方法是使用Java 8的泛型和功能接口的组合:

public class Wrapper<P1> {
    @FunctionalInterface
    public interface TriFunction<P1, P2, P3, R> {
        R apply(P1 p1, P2 p2, P3 p3);
    }

    private P1 value;

    public Wrapper(P1 value) {
        this.value = value;
    }

    public <R> R invoke(Function<P1, R> func) {
        return func.apply(value);
    }

    public <R, P2> R invoke(BiFunction<P1, P2, R> func, P2 value2) {
        return func.apply(value, value2);
    }

    public <R, P2, P3> R invoke(TriFunction<P1, P2, P3, R> func, P2 value2, P3 value3) {
        return func.apply(value, value2, value3);
    }
}

您可以将此包装器与方法引用(:: operator)一起使用,如下所示:

public class A {
    public String identity(String value) {
        return value;
    }

    public String concat(String value1, String value2) {
        return value1 + value2;
    }

    public String concat(String value, int val) {
        return value + val;
    }

    public String concat(String value1, String value2, int val) {
        return value1 + value2 + val;
    }

    public static void main(String[] args) {
        Wrapper<String> wrapper = new Wrapper<>("toto");
        A a = new A();
        wrapper.invoke(a::identity);           // returns "toto"
        wrapper.invoke(a::concat, "tutu");     // returns "tototutu"
        wrapper.invoke(a::concat, 10);         // returns "toto10"
        wrapper.invoke(a::concat, "tutu", 10); // returns "tototutu10"
    }
}

此解决方案引入了简单类型的装箱,因此您可能希望提供接受invokeIntFunction等的ObjIntFunction方法。它也只处理最多3个参数的调用方法,但我认为处理更多的模式很容易理解。