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

时间:2012-12-22 11:22:25

标签: 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 
    } 
}

5 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

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

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