私はほとんど制御できないファクトリーから私に渡されたオブジェクトのメソッドをオーバーライドしたいと思います。
私の特定の問題は、(SocketObjectのgetInputStreamおよびgetOutputStreamをオーバーライドしてwire logging。
一般的な問題は次のとおりです。
public class Foo {
public Bar doBar() {
// Some activity
}
}
インスタンス化されたFoo
を取得し、doBar
を次のように動作する自分のものに置き換えたい場合:
Bar doBar() {
// My own activity
return original.doBar();
}
ソケットの場合、ロギングによってラップされてデータをインターセプトするInputStreamおよびOutputStreamを返します。
Javaはクラスベースのオブジェクト指向を使用するため、これは不可能です。実行できることは デコレータパターン を使用することです。つまり、ラップされたストリームを返すオブジェクトのラッパーを記述します。
あなたが望む効果を達成する方法はあると思います。もともとはボタン付きのスイングで使用され、クリックしたときにプログラマがボタンに何かをさせることができるのを見ました。
Fooクラスがあるとします。
public class Foo {
public Bar doBar() {
// Some activity
}
}
次に、ランナークラスまたは類似のクラスがあります。インスタンス化の時点でdoBar()メソッドをオーバーライドすると、その特定のオブジェクトにのみ影響します。
そのクラスは次のようになります。
public class FooInstance{
Foo F1 = new Foo(){
public Bar doBar(){
//new activity
}
}
Foo F2 = new Foo();
F1.doBar(); //does the new activity
F2.doBar(); //does the original activity found in the class
}
私はそれがあなたのためのトリックを行うことを完全に確信していませんが、おそらくそれはあなたを正しい方向に設定するでしょう。他にクラス外のメソッドをオーバーライドすることが可能である場合、それが役立つかもしれません。
既存のオブジェクトのメソッドを置き換えることはできません。たとえば、既存のオブジェクトのタイプを変更することはできません。
既存のインスタンスに対して委任である別のクラスの新しいインスタンスを作成することもできますが、これにも制限があります。
実際のケースでは、ソケットから返されたストリームをラップするために別の呼び出しを行うだけの方法はありませんか?詳細を教えてください。
ソケットがインターフェースの場合、動的プロキシを作成できます。以下に例を示します。他の人がこれを行う必要があり、ターゲットインスタンスがインターフェイスのインスタンスである場合に備えて、ここに配置します。
これがソケットで機能しない主な理由は、Java.lang.reflect.Proxy.newProxyInstance
は2番目の引数にインターフェースの配列を必要とするため、クラスはここでは機能しません。そのため、この例では、ParentInterface
というインターフェイスを作成する必要がありました。これには、3つの印刷メソッドしかありません。
public class Parent implements ParentInterface {
@Override
public void print1() {
System.out.println("parent 1");
}
@Override
public void print2() {
System.out.println("parent 2");
}
@Override
public void print3() {
System.out.println("parent 3");
}
public static void main(String[] args) {
Parent originalInstance = new Parent();
ParentInterface proxied = (ParentInterface) Java.lang.reflect.Proxy.newProxyInstance(
Parent.class.getClassLoader(),
new Class[]{ParentInterface.class},
new ParentProxy(originalInstance));
proxied.print1();
proxied.print2();
proxied.print3();
}
static class ParentProxy implements InvocationHandler {
final Object realObject;
public ParentProxy(Object real) {
realObject = real;
}
@Override
public Object invoke(Object target, Method m, Object[] args) throws Throwable {
try {
if (m.getName().equals("print2")) {
print2();
return null;
} else {
return m.invoke(realObject, args);
}
} catch (Java.lang.reflect.InvocationTargetException e) {
throw e.getTargetException();
}
}
public void print2() {
System.out.println("wrapper 2");
}
}
}
これが可能かどうかはわかりません。独自のクラスを作成し、ファクトリによってメンバーとして返されたオブジェクトを持ち、そのクラスのdoBar()メソッドを記述することを検討しましたか?.
2つのオプション:
別のプロキシ関連ソリューション:Aspectsを使用して、自分でサブクラス化せずに特定のオブジェクトのメソッドをオーバーライドできます。これはロギングに特に適切で一般的です。この例では、spring-aopを使用しています。
class Example {
final Foo foo;
Example(Foo original) {
AspectJProxyFactory factory = new AspectJProxyFactory();
factory.setTarget(original);
factory.addAspect(FooAspect.class);
foo = (Foo) factory.getProxy();
}
@Aspect
static class FooAspect {
@Before("execution(Foo.doBar())")
Object beforeDoBar() {
// My own activity
}
}