web-dev-qa-db-ja.com

入れ子になったスイッチケースのリファクタリングを伴う大きなメソッド(Java)

基本的に私は、複数の入力に対して数学の変換と評価を行うように設計されたクラスの2つの巨大なメソッドに一連の数式を持っています。入力が実際に入力のリストである場合(いくつかの合計も含まれるため)。後で、GPU/CPUで高速化された行列の乗算と加算を利用してこのコードを最適化したいのですが、今は基本的なforループを使用しています。

仮に、私は数十のケースに成長したいとし、今は10未満です。

何かのようなもの:

enum EnumType {
    SUPER_FUNCTION,
    MEGA_FUNCTION,
    ..
}

float doMathStuff(EnumType functionType, List<float> a, List<float> b...) {
    switch(functionType) {
        case SUPER_FUNCTION:
                    if(situationA) {
                        switch(something else) {

                        }
                    } else {
                        switch(something else) {

                        }
                    }
                return stuff;
        case MEGA_FUNCTION:
                for(..) {
                    if(situationA) {
                        switch(something else) {

                        }
                    } else {
                        switch(something else) {

                        }
                    }
                }
                return stuff;
        ...
    }
}

私の問題は、関数をサポートするために、各switchステートメントで数百行のコードになってしまい、処理がかなり面倒になることです。ケースを追加したら、これを維持することを考えて身震いします。

この悪夢の進行を抑える方法に関するアイデアはありますか?

ところで:これは私自身の個人的なプロジェクトであり、私にはどんな変更をすることも完全に自由です。

2
Akumaburn

私が書いた多項式計算ライブラリについても、同様の設計目標がありました。いくつかの特別な最適化の可能性があるいくつかの種類の操作が必要でした。

簡単に言えば、オブジェクト指向は、正しく実行されれば、非常に役立ちます。

実際のドメインを指定していないので、多項式の例を使用してみましょう。多項式に関するものなので、もちろんPolynomialを作成しました。

_public interface Polynomial {
   Polynomial add(Polynomial other) { ... }

   Polynomial dot(Polynomial other) { ... }

   ...etc...
}
_

ただし、特殊なケースがあります。たとえば、多項式がモジュロである場合、それらの束を追加すると、モジュロ演算が遅延する可能性があり(かなり高価です)、計算をGPUにエクスポートできます。

Polynomialsの束を追加することは、より高度な操作であるため、これらを追加するPolynomialRingに追加しました。つまり、

_public class PolynomialRing {
   ...
   public Polynomial add(Polynomial[] ps) { ... }
   ...
}
_

最初はこれはPolynomial.add()を使用したforループでしたが、例のように、後でモジュロを遅延させ、JVMがSIMD命令に変換する構成を使用するように最適化しました。

したがって、数学ドメインを適切にモデル化する必要があります。すべてのための一般的なメカニズムはありません。あなたがしたい、または最適化したいすべてのものについて、場所を見つける必要があります。

2

minimumで、動作の一部をカプセル化する(そしてコードを整理する)関数を作成する必要があります

_float doMathStuff(EnumType functionType, List<float> a, List<float> b...) {
  switch(functionType) {
    case SUPER_FUNCTION: return handleSuperFunction(args); break;       
    case MEGA_FUNCTION: return handleMegaFunction(args); break;
  }
}

float handleSuperFunction(someArgs) {
  if(situationA) {
    return handleSuperSituationA(args);
  }
  else {
    return handleSuperSituationB(args);
  }
}

float handleSuperSituationA(args) {
  switch(something else) {
    case foo: return blah;
    ...
  }
}
_

これを行うと、あなたや他の人が読んで従うことが容易になります。次に、これらが「オブジェクト」の関数であり、ポリモーフィックにすることができるかどうかを検討します。ドメインを知らなければ、これを言うのは難しいです。

追加

1つの大きな利点は、さまざまなサブケースをnameできることです。たとえば、handleImaginaryRoot()handleRealRoot()などです。 (私の分析数学は少し古くなっています、YMMV ...)

4
user949300