3

メソッドが 1 つしかないインターフェイスがあります。オブジェクトを受け取る静的関数があり (これらのオブジェクトはインターフェイスを実装します)、インターフェイスで定義されているメソッドの実装をオブジェクトでオーバーライド/置換したいと考えています。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 
    } 
}
4

5 に答える 5

2

すべてのメソッド呼び出しをオブジェクトに委任する同じインターフェイスを持つクラスを作成してから、それを拡張する匿名クラスを作成し、必要なものをオーバーライドできます

間取り:

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
    };
}
于 2012-12-22T11:23:54.397 に答える
1

この種の動的動作は、Java では直接サポートされていません。しかし、オブジェクトが協力すると、このようなことが実現できます。つまり、次の実装を変更するメソッドを提供できますmyMethod

void changeMethod(MyInterface other) {
    realImpl = other;
}
Object myMethod (Object obj) {
    return realImpl.myMethod(obj);
}
于 2012-12-22T11:34:28.643 に答える
1

装飾している正確なオブジェクトの種類を知らなければ、一般的にこれを行うことはできません。それがわかっていれば、実装を変更してその特定のクラスのサブクラスを作成できます。Java の型システムは、必要に応じてインターフェイスの実装を組み合わせて一致させるほど柔軟ではありません。

メソッドに渡すすべてのオブジェクトに対して動的プロキシを作成する動的クラス定義手法に頼ることもできdecorateますが、そのようなアプローチでは桁違いに複雑になります。

于 2012-12-22T11:30:27.413 に答える
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;
  }
}
于 2012-12-22T11:33:07.037 に答える
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));
      }
  }
于 2012-12-22T11:31:01.733 に答える