パスワードを忘れた? アカウント作成
30626 journal

rutoの日記: Javaで、C++のクラス内typedefっぽいことをやる

日記 by ruto

『ジェネレーティブプログラミング』という本を読んでいる。といっても前半は飛ばしたし、後半もあまり読めてないんだけど。
そこで構成レポジトリというのがでてきておもしろい。

例えば行列計算ライブラリを作るとする。
行列は要素の型がfloatだったりdoubleだったり複素数だったり、行列で使うベクトルの型も行列の種類によって違ったりして、その組み合せは膨大になる。
そのため、C++ならテンプレートを使って、行列クラスは要素の型やベクトルの型を受け取るようにするとよい。
つまり、

template<class ElementType, class VectorType>
class Matrix {
  (ElementTypeやVectorTypeをここで使う)
}

みたいな感じ。
このとき、要素の型とベクトルの型を両方いちいち指定するのはめんどうなので、まとめてどこかに1つだけ書いておいて、それを参照するようにできると便利。
それが構成レポジトリと呼ばれるものである。つまり、

struct FooConfigrationRepository {
  typedef double ElementType;
  typedef FooVector<ElementType> VectorType;
}

と書いておいて、

template<class Config>
class Matrix {
  (ElementTypeの代わりにConfig::ElementTypeを使う)
}

という風にMatrixの方を書き換えておけば、FooConfigrationRepository1つを渡すだけで済むので楽だし、後で変更するときもここだけ変えればいいので楽になる。

というのが構成レポジトリのごく簡単な説明。
ただ、『ジェネレーティブプログラミング』ではC++での例は載っているけど、Javaの例は載っていない。
そもそもJavaではクラス内でtypedefできないのでC++と同じようにはできない。

しかし、JavaでもGenericsを使えば似たようなことはできる。
まず、構成レポジトリは次のように書く。

interface ConfigrationRepository<ElementType extends ElementInterface, VectorType extends VectorInterface<ElementType>> {
  VectorType createVector(int size);
  ...
}
 
class FooConfigrationRepository implements ConfigrationRepository<Double, FooVector<Double>> {
  public FooVector<Double> createVector(int size) {...}
  ...
}

それで、受け取る方は次のように書く。

class Matrix<ElementType extends ElementInterface, VectorType extends VectorInterface<ElementType>, Config extends ConfigrationRepository<ElementType, VectorType>> {
  (ElementTypeやVectorTypeを使う)
}

それで、これらのライブラリを使う場合には次のようにする。

class Main {
  public static void main(String [] args) {
    start(new FooConfigrationRepository());
  }
  <ElementType extends ElementInterface, VectorType extends VectorInterface<ElementType> Config extends ConfigrationRepository<ElementType, VectorType>> void start(Config config) {
      Matrix<ElementType, VectorType, Config> bar = new Matrix<ElementType, VectorType, Config>(config);
      ...
  }
}

つまり、例えばFoo<Double, Integer>という型を、2つの型DoubleとIntegerを要素として持つレコードとして使っている。
そこから要素を取り出すときは、<X, Y, Z extends Foo<X, Y>>という風にパターンマッチを使って取り出している。

ただ、C++に比べて記述はかなり汚なくなっていてあまり実用的ではないし、ここまで凝ったことはJavaではやらないのがJavaの流儀っぽい気がする。

# JavaのGenericsっていままで詳しく調べたことなかったので、実はもっとスマートな方法があるかもしれない。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
typodupeerror

人生の大半の問題はスルー力で解決する -- スルー力研究専門家

読み込み中...