繁体   English   中英

替换/覆盖对象的方法,该方法是Java中接口的实现

[英]Replace/override method of an object which is an implementation of an interface in Java

我有一个只有一种方法的接口。 我有一个接收对象的静态函数(这些对象实现了接口),我想覆盖/替换在接口中定义的方法的实现。 在Java中执行此操作的最佳方法是什么

public class MyClass {

    public interface MyInterface {
         Object myMethod (Object blah);
    }

    public static MyInterface decorator(MyInterface obj) { 
          //I want to return a version of obj
          //with a different implementation of myMethod
          //everything else in obj should be same, except myMethod 
    } 
}

您可以使用相同的接口创建一个类,该类接受所有方法调用您的对象,然后创建一个匿名类来扩展它并覆盖您想要的任何内容

Intercace:

Interface MyInterface {
    void m1();
    void m2();
}

委派课程:

class MyDelegate implements MyInterface {
    private MyInterface delegate;

    MyDelegate(MyInterface delegate) {
        this.delegate = delegate;
    }

    void m1() {
        delegate.m1();
    }

    void m2() {
       delegate.m2();
    }
}

在静态方法中,您创建一个扩展MyDelegate的匿名类的实例并覆盖您想要的任何内容,其余的将由obj运行

static MyInterface wrap(MyInterface obj) {
    return new MyDelegate(obj) {
        void m1() {
            // overrided m1
        }

        // my will eventually get to obj
    };
}

如果不了解您正在装饰的确切对象类型,则通常无法做到这一点。 如果你知道它,那么你可以创建一个特定类的类,并改变实现。 Java的类型系统不够灵活,无法根据需要混合和匹配接口实现。

可以使用动态类定义技术,这将为您传递到decorate方法中的每个对象创建动态代理,但在这种方法中复杂度要高出一个数量级。

Java中不直接支持这种动态行为。 但是当对象合作时,你可以实现类似的东西。 即它可以提供一种方法来改变myMethod的实现:

void changeMethod(MyInterface other) {
    realImpl = other;
}
Object myMethod (Object obj) {
    return realImpl.myMethod(obj);
}

使用CGLib,您可以在运行时实现接口。

示例 -

public class KeySample {
      private interface MyFactory {
         public Object newInstance(int a, char[] b, String d);
      }
      public static void main(String[] args) {
          MyFactory f = (MyFactory)KeyFactory.create(MyFactory.class);
          Object key1 = f.newInstance(20, new char[]{ 'a', 'b' }, "hello");
          Object key2 = f.newInstance(20, new char[]{ 'a', 'b' }, "hello");
          Object key3 = f.newInstance(20, new char[]{ 'a', '_' }, "hello");
          System.out.println(key1.equals(key2));
          System.out.println(key2.equals(key3));
      }
  }

如果我们可以将它限制为接口(任意数量的接口),那么您正在寻找动态代理。

所以你的问题:如果你先调用该接口中的方法而不调用装饰器然后再使用装饰器调用你需要不同的行为,那么给定这个接口实现:

MyInterface o = new MyInterface() {
    public Object myMethod(Object blah) {
        return "bar";
    }
};

这应该做不同的事情,例如改变返回值(和/或其他):

System.out.println(o.myMethod(null));
o = decorator(o);
System.out.println(o.myMethod(null));

输出:

bar
foo

这可以使用java中的动态代理完成:

public static MyInterface decorator(final MyInterface obj) { 
  InvocationHandler handler = new InvocationHandler() {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      if (method.getName().equals("myMethod")) {
        //do something special
        return "foo";
      }
      return method.invoke(obj, args);
    }
  };


  MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
                            MyInterface.class.getClassLoader(),
                            obj.getClass().getInterfaces(), //all or limit it to just one or a few
                            handler);
  return proxy;
}

更新:如果您想涉及更多接口(上面更新的代理实例代码以实现接口而不是硬编码):

现在让这个工作:

 public static void main(String[] args) {
        A o = new A();
        System.out.println(o.myMethod(null));
        System.out.println(o.myOtherMethod(1));
        Object o2 = decorator(o);
        System.out.println(((MyInterface) o2).myMethod(null));
        System.out.println(((MyInterface2) o2).myOtherMethod(1));
 }

随着输出:

bar
2
foo <-- changed
2 <- the same behavior

鉴于:

class A implements MyInterface, MyInterface2 {
  @Override
  public Object myMethod(Object blah) {
    return "bar";
  }

  @Override
  public int myOtherMethod(int a) {
    return a+1;
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM