2015-11-06 12 views
8

私はのJavaで特定のタイプのインタフェースを作成しようとしています(通常のクラスにも同じですが)。このインタフェースには、たとえばinvokeのようないくつかのメソッドが必要です。提供されるジェネリック型引数に応じて、さまざまな量のパラメータで呼び出されます。一例として、Javaでは、任意の量のジェネリック型パラメータを指定できますか?

public interface Foo<T...> { 
    public void invoke(T... args); 
} 

// In some other class 
public static Foo<Float, String, Integer> bar = new Foo<Float, String, Integer>() { 
    @Override 
    public void invoke(Float arg1, String arg2, Integer arg3) { 
     // Do whatever 
    } 
}; 

これはを使用(およびいくつかのコンテキストを提供する)ことができる方法、簡単に説明するためには、クラスDelegatorを考えてみましょう。このクラスは、一般的な種類の様々な数をとり、これらのパラメータタイプを持つ単一のメソッド(invoke)があります。このメソッドは、そのパラメータをリスト内のオブジェクトに渡します:IDelegateのインスタンス。同じジェネリック型を取ります。これにより、Delegatorは、パラメータタイプの特定のリストごとに新しいクラスを作成することなく、いくつかのデリゲートメソッド(IDelegateで定義)の中から選択することができます。

このようなものはありますか?私はvariadic templatesをC++で読んだことがありますが、Javaでこれと似たものは見つかりません。そんなことはありますか?そうでない場合、同じデータモデルをエミュレートする最もクリーンな方法は何でしょうか?

答えて

4

このようなものはありますか?私はvariadicテンプレート をC++で読んだことがありますが、Javaでこれと似たものは見つかりません。そのようなものは が利用可能ですか?

いいえ、この機能はJavaでは使用できません。

2

いいえ、直接利用できるものはありません。しかし、あなたがTupleクラスとライブラリを使用する場合は、単にインターフェイス

interface Foo<T> { 
    void invoke(T t); 
} 

を作ることによって、それをシミュレートすることができます(このインタフェースは、本質的にConsumer<T>と同じである。)

その後、あなたは一例

のために行うことができ
Foo<Tuple<String, Integer, Date, Long>> foo = new Foo<>() { 
    ... 
} 

パラメータ数ごとに別々のTupleタイプが必要です。 4つのパラメータに対してTupleクラスがあり、5つではない場合は、Pairクラスを使用して余分なパラメータを絞り込むことができます。

このようにタプルタイプを入れ子にすると、無制限の数のパラメータが得られます。しかし、これらの回避策は実際には醜いので、私はそれらを使用しません。

+0

このようにするには、 'Pair 'で十分でしょう。しかし、誰も 'ペア >>>'を望んでいないので、このようなことは通常異なる方法で解決されます。型の安全性を完全に破棄するか、http://www.javatuples.org/のような図書館で – Marco13

2

あなたが提供した文脈では、Listをパラメータとして使用することをお勧めします。これらのパラメータに共通するものがある場合は、List<Object>ではなく、リストを<T extends CommonParrent>に拘束できます。そうでない場合は、マーカーインターフェイスを使用することができます。

ここは例です。

public class Main { 

    public static void main(String[] args) { 
     delegate(asList(new ChildOne(1), new ChildTwo(5), new ChildOne(15))); 
    } 

    private static <T extends Parent> void delegate(List<T> list) { 
     list.forEach(item -> { 
      switch (item.type) { 
       case ONE: delegateOne((ChildOne) item); break; 
       case TWO: delegateTwo((ChildTwo) item); break; 
       default: throw new UnsupportedOperationException("Type not supported: " + item.type); 
      } 
     }); 
    } 

    private static void delegateOne(ChildOne childOne) { 
     System.out.println("child one: x=" + childOne.x); 
    } 

    private static void delegateTwo(ChildTwo childTwo) { 
     System.out.println("child two: abc=" + childTwo.abc); 
    } 

} 

public class Parent { 
    public final Type type; 

    public Parent(Type type) { 
     this.type = type; 
    } 
} 

public enum Type { 
    ONE, TWO 
} 

public class ChildOne extends Parent { 
    public final int x; 

    public ChildOne(int x) { 
     super(Type.ONE); 
     this.x = x; 
    } 
} 

public class ChildTwo extends Parent { 
    public final int abc; 

    public ChildTwo(int abc) { 
     super(Type.TWO); 
     this.abc = abc; 
    } 
} 

このソリューションの最大の欠陥は、子どもたちがswitch文のキャストに対応している必要があり列挙経由で自分のタイプを指定する必要があり、そうあなたはこれら二つの場所の1つを変更するたびに、あなたが覚えておく必要がありますということですコンパイラはこれをあなたに伝えないので、もう一方を変更してください。このような間違いは、コードを実行して特定の分岐を実行することによってのみ検出されるため、テスト駆動型の開発が推奨されます。

関連する問題