4

ビジター パターンで Java ジェネリックを使用する場合、私はある種の問題を抱えています。

私のコードは次のようなものです:

public interface MyInterfaceVisitor<A, B> {
    public A visitMyConcreteObject(MyConcreteObject object, B parameter);
}

public interface MyObject {
    public <A, B> A accept(MyInterfaceVisitor<A, B> visitor, B parameter);
}

public class MyConcreteObject implements MyObject {
    @Override
    public <A, B> A accept(MyInterfaceVisitor<A, B> visitor, B parameter) {
        return visitor.visitMyConcreteObject(this, parameter);
    }
}

public class MyConcreteVisitor implements MyInterfaceVisitor<????> {

    @Override
    public <X extends C> X visitMyConcreteObject(MyConcreteObject object, Class<X> parameter) {
        // Do a lot of things.
        // Return an instance of the given class.
    }

    // This method is the entry point of the MyConcreteVisitor.
    public <X extends C> void someOtherMethod(Class<X> parameter) {
        MyObject m = ...;
        X x = m.accept(this, parameter);
        ...;
    }
}

public class C {}
public class Dog extends C {}
public class Cat extends C {}

public class Client {
    public static void main(String... args) {
        MyConcreteVisitor v = new MyConcreteVisitor();
        v.someOtherMethod(Cat.class);
        v.someOtherMethod(Dog.class);
    }
}

// We have other implementations of the visitor that does not matters, like this one.
public class SomeOtherConcreteVisitor implements MyInterfaceVisitor<String, Integer> {
    @Override
    public String visitMyConcreteObject(MyConcreteObject object, Integer parameter) {
        return "foo";
    }
}

???? の一般的な署名を見つける必要があります。これにより、コードがコンパイル可能になり、MyConcreteVisitor クラスのオーバーライドされたメソッドが MyInterfaceVisitor インターフェイスのシグネチャと一致するようになります。

MyInterfaceVisitor インターフェイスの visitMyObject の署名も、そのジェネリックも変更できません。これは、MyInterfaceVisitor の他の実装が存在し、それらのジェネリックが MyConcreteVisitor のジェネリックとは何の関係もないために発生します。

MyConcreteVisitor クラスにはジェネリック自体があってはならないため、コンパイラはMyConcreteVisitor v = new MyConcreteVisitor();unchecked または rawtypes 警告を生成せずに a を許可する必要があります。

具体的な visitMyObject を変更public C visitMyObject(MyObject object, Class<? extends C> parameter)して ???? を宣言すると as として<C, Class<? extends C>>、someOtherMethod にキャストを追加する必要があります。

unchecked または rawtypes の警告を受けたり、インターフェイスを変更したり、キャストを追加したりせずに、ジェネリック型を定義してコンパイル可能にする方法は? これはJavaでも可能ですか、それともジェネリックを乱用しすぎていますか?

4

2 に答える 2

2

問題は、実装がX extends Cメソッドに別の型パラメーターを導入し、それを使用してパラメーターをvisitMyConcreteObject解決しようとBしていることです。visitMyConcreteObjectでジェネリックにすることはできませんが、たとえば、によってパラメータ化された型でX解決しようとします。これは、クラス宣言で解決されますが、クラスのメソッドによってのみ宣言されるためです。BXClass<X>BX

私が見ることができることから、あなたには2つの選択肢があります。どちらかでMyConcreteVisitorジェネリックにするX

public class MyConcreteVisitor<X extends C> implements MyInterfaceVisitor<X, Class<X>> {

    @Override
    public X visitMyConcreteObject(MyConcreteObject object, Class<X> parameter) {
        // Do a lot of things.
        // Return an instance of the given class.
    }
}

または、タイプの安全性を取り除いXて失います(具体的なタイプを超えてC):

public class MyConcreteVisitor implements MyInterfaceVisitor<C, Class<? extends C>> {

    @Override
    public C visitMyConcreteObject(MyConcreteObject object, Class<? extends C> parameter) {
        // Do a lot of things.
        // Return an instance of the given class.
    }
}
于 2013-01-28T16:19:50.703 に答える
1

私はこれがあなたが探しているものだと思います:

public class MyConcreteVisitor implements MyInterfaceVisitor<Object,Class<?>> {

    @Override
    public Object visitMyConcreteObject(MyConcreteObject object, Class<?> parameter) {
        // Do a lot of things.
        // Return an instance of the given class.
    }

    // This method is the entry point of the MyConcreteVisitor.
    public <X> void someOtherMethod(Class<X> parameter) {
        MyObject m = ...;
        X x = parameter.cast(m.accept(this, parameter));
        ...;
    }
}
于 2013-01-28T16:14:03.550 に答える