オブジェクトがどのクラスに属しているかを知らなくても、そのメソッドを持つオブジェクトで「getProgram」を呼び出せるようにしたいと考えています。ここでインターフェイスを使用する必要があることはわかっていますが、他の人のコードを使用していて、使用しているクラスを再設計できません。BeanUtils.getProperty が役立つかもしれないと思ったのですが、文字列しか返さないようです。キャスト可能なオブジェクトを返す Beanutils.getProperty のようなものはありますか? または、インターフェイスを共有しない 2 つの類似したクラスを操作する別のよりスマートな方法はありますか? ありがとう -モーガン
7 に答える
BeanUtils の代わりに PropertyUtils (apache commons-beanutils から) を使用します。
String の代わりに Object を返す getProperty(Object bean, String name) メソッドがあります。
詳細については、JavaDocを参照してください。
これにはリフレクションを使用してください...次の例は、共通のインターフェースを持たないオブジェクトでそれを行う方法を示しています。
public static void main(String[] args) throws Exception {
doSomething(new A());
doSomething(new B());
}
private static void doSomething(Object object) throws Exception {
Method m = object.getClass().getMethod("doSomething", (Class[])null);
m.invoke(object, (Object[])null);
}
private static class A {
public void doSomething() {
System.out.println("I'm doing it already!");
}
}
private static class B {
public void doSomething() {
System.out.println("I'm doing it too!");
}
}
Java 5+ を使用している場合は、わずかに短いバージョン
public static void main(String[] args) throws Exception {
System.out.println(invoke("toString", new A());
System.out.println(invoke("toString", new B());
}
private static <R> R invoke(Object object, String methodName) throws Exception {
return (R) object.getClass().getMethod(methodName).invoke(object);
}
おそらく、このメソッドを実装するクラスの数は有限であり、それらに直接リンクできます。だから反省はいらない。反射は悪です。
次のメソッドを持つ一連のクラスがあるとします。
public class LibA { public Program getProgram() { return program; } ... };
public class LibB { public Program getProgram() { return program; } ... };
...
次に、インスタンスとキャストのペアが必要です。これをメソッドに入れると、一度だけ実行する必要があります。
public static Program getProgram(Object obj) {
if (obj instanceof LibA) {
return ((LibA)obj).getProgram();
} else if (obj instanceof LibB) {
return ((LibB)obj).getProgram();
} else {
throw new IllegalArgumentException(obj+" doesn't have a known getProgram");
// Or an appropriate application exception.
}
}
または、アダプターを使用することもできます。
public interface ProgramContainer {
Program getProgram();
...
}
public class LibAContainer implements ProgramContainer {
private final LibA libA;
public LibAContainer(LibA libA) {
this.libA = libA;
}
public Program getProgram() {
return libA.getProgram();
}
...
}
リフレクション APIを参照してください。
Class.getMethod() (または getMethods()) を使用して、適切なメソッドを見つけて呼び出します。
非常に単純な解決策: インターフェイスを実装する委任を使用します。
interface GetProgram
{
String getProgram ();
}
class AWrapper implements GetProgram
{
A a;
public AWrapper (A a) { this.a = a;
String getProgram () { return a.getProgram(); }
}
これで、元のクラスに触れることなく、コードでインターフェイスを使用できます。
欠点: A が手の届かない場所に作成されている場合、これはうまく機能しません。A が一度自分の管理下で作成され、すぐにラップできる場合に最適です。
java.beans.Expressionは、レシーバーの具象クラスでメソッドにアクセスできる限り、これを実行します。
public static void main(String[] args) throws Exception {
new Expression(new A(), "doSomething", null).getValue();
new Expression(new B(), "doSomething", null).getValue();
}
public static class A {
public void doSomething() {
System.out.println("I'm doing it already!");
}
}
public static class B {
public void doSomething() {
System.out.println("I'm doing it too!");
}
}