私がこのインターフェースを持っているとしましょう:
interface Foo<T extends Foo<T>> { // ... }
そして、それを実装する次の 3 つのクラス:
class TrueFoo implements Foo<TrueFoo > { // ... }
class FalseFoo implements Foo<FalseFoo> { // ... }
class WrongFoo implements Foo<FalseFoo> { // ... }
// ^^^^^^^^ this here is wrong, only
// Foo<WrongFoo> should be allowed
次のメソッドのメソッド シグネチャは、TrueFoo または FalseFoo 型のオブジェクトを返すことができるが、WrongFoo 型のオブジェクトを返さないことを強制するには、どのようなものである必要がありますか?
public ???? getFoo(boolean which) {
return which ? new TrueFoo() : new FalseFoo();
}
以下は機能しません。
これにより、新しい WrongFoo() を返すこともできます。
public Foo<?> getFoo(boolean which) { return which ? new TrueFoo() : new FalseFoo(); }
これにより、何も返すことができません(説明は次のとおりです):
public <FooType extends Foo<FooType>> FooType getFoo(boolean which) { return which ? new TrueFoo() : new FalseFoo(); }
問題は、FooType の型が、
getFoo()
実際に返そうとするオブジェクトではなく、関数を呼び出すコンテキストによって決定されることです。
ちなみに、メソッドを呼び出すときにこの署名を強制するのは簡単です。
public <FooType extends Foo<FooType>> void test(FooType foo) {
// Do something with foo
}
これを WrongFoo のインスタンスで呼び出そうとすると、バインドされた不一致エラーが発生します。
メソッドの戻り値の型にもこれを行う方法があるはずだと思います。
または、Foo のインターフェイス定義に既にこの署名を強制する方法はありますか?
編集:
このインターフェイスが何をするべきかを視覚化するために、たとえば次のバージョンについて考えることができます。
interface CanCopy<Type extends CanCopy<Type>> {
public Type copy();
}
明らかにクラス likeFoo implements CanCopy<Bar>
は意味をなさず、Foo implements CanCopy<Foo>
orだけBar implements CanCopy<Bar>
です。
編集2:
ソリューションが存在するという概念実証と同様に、次のヘルパー クラスを自分で定義できます。
class FooResult {
private final Foo<?> foo;
public <FooType extends Foo<FooType>> FooResult(FooType foo) {
this.foo = foo;
}
@SuppressWarnings("unchecked")
public <FooType extends Foo<FooType>> FooType getFoo() {
return (FooType) foo;
}
}
次に、 getFoo メソッドを次のタイプにするように要求できます。
public FooResult getFoo(boolean which) {
return which ? new FooResult(new TrueFoo()) : new FooResult(new WrongFoo());
}
そうすれば、get メソッドから WrongFoo を返すことができなくなります。
しかし、これは明らかに、Javaジェネリックが通常コードを作成する傾向があるのと同じくらいエレガントであるには少し複雑すぎます(私の経験では)...では、これを何とか短縮できますか?
編集3:
次のように定義することで、インターフェイスを実装している人にチェックを提供する別の方法を見つけました。
interface Foo<FooType extends Foo<FooType>> {
// Other interface definitions
/**
* Please implement with just this line in it:<br/><br/>
* <code>return this;</code>
* @return <code>this</code>
*/
public FooType returnThis();
}
ここで、誰かが上記のように WrongFoo クラスを実装しようとすると、メソッドを提供する必要があり、doctype で要求FalseFoo returnThis()
されているとおりに単に実装するとreturn this
、その行でエラーがスローされます。
これは保証ではありませんが、クラスの不注意なコピーによるミスに対するかなり良いダミーチェックです...そして、とにかくこの署名付きのメッセージが必要な場合には、それは素晴らしい解決策になるでしょう.
他にアイデアはありますか?