数学演算を実行するためのポリモーフィックコードを設計しています。ユースケースが異なれば必要な表現も異なるため、データの基礎となる表現を抽象化するという考え方です。操作は、同じタイプのデータでのみ実行できます。
これらのものを操作する多くのアルゴリズムがあり、これらのアルゴリズムは多くの操作を必要とするためです。したがって、IMOの最適な設計は、多態的な操作を定義する基本インターフェイスを作成し、各データ型をそのインターフェイスの実装にすることです。
interface Datum<D extends Datum<D>> {
D fuzz();
D Fuse(D that);
D fizz(int base);
}
class MadDatum extends Datum<BigDatum> {
...
}
ただし、表現ごとに特定の定数を定義する必要もあります。 Datum
の実装にとらわれない一般的なアルゴリズムが正しいタイプの定数をきれいに取得できるように、これらの定数に多態的にアクセスしたいと思います。定数はDatum
に依存しないため、定数をメソッドとして定義することは実際には意味がありません。しかし、私が考えることができる唯一の合理的な代替案は、データのtypeを表す並列型階層を作成することです。
interface DataType<D extends Datum<D>> {
D warpTorsion();
D meltingAngle();
}
ただし、メソッドはタイプとデータの両方を取得する必要があります。
<D extends Datum<D>> D newmansMethod(DataType<D> type, Collection<D> data);
この設計は、コンパイラがチェックしない方法でクラス階層を複製するため、扱いにくくなります。データを簡単に実装でき、対応するDataTypeの実装を忘れることができます。また、場合によっては数百のメソッドに追加のメソッドパラメータが必要になります。
Haskellは、定数/「nullary関数」を型クラスで指定できるため、この問題に対する洗練された解決策を認めていることを私は知っています。この機能をJavaで複製するクリーンな方法を知っている人はいますか?
私があなたの質問を正しく理解したなら、あなたはabstract static
を探しています。これはJavaでは不可能ですが、いくつかの回避策があります: https://stackoverflow.com/questions/1916019/Java-abstract-static-workaround 。別の方法として、Scalaなど、これを許可する他の言語を使用することもできます
Haskellスタイルを使用することもできます(Haskellの実装では、最も一般的なケースでは、型クラスの要件ごとに1つの非表示の引数を渡すことができます)。
基本型Datum
を削除し、それに関連するすべての興味深いメソッドをDataType
に移動します。
interface DataType<D> {
D fuzz(D datum);
D Fuse(D datum1, D datum2);
D fizz(D datum, int base);
D warpTorsion();
D meltingAngle();
}
次に、次のようになります。
<D> D newmansMethod(DataType<D> type, Collection<D> data);
そして、興味深いもののほとんどすべてがDataType
の実装にあるため、それを実装することを忘れることは非常に困難です。ライブラリを認識しない既存の型を改造して、独自のDataType
を実装することもできます。
JITerは、すべてのメソッドディスパッチが同じDataType
オブジェクトから離れているために呼び出されるメソッドについてより多くを推測できるため、処理を高速化できる可能性がありますが、それが違いを生むかどうかはわかりません。実際には。