私はいくつかの巨大な switch ステートメント ブロックを含むプロジェクトを継承しました。いくつかのブロックには最大 20 のケースが含まれています。これらを書き換える良い方法は何ですか?
11 に答える
なぜそれらを別の構造に書き直したいのですか?個別に処理する必要があるケースが本当に 20 件ある場合は、スイッチ/ケースが最適です。if/then ロジックの大きなチェーンを維持するのは恐ろしいことです。
オブジェクト指向言語を使用している場合、ポリモーフィズムは別のオプションです。各サブクラスは、メソッドに独自の機能を実装します。
他の人が指摘したように、switch ステートメントに依存します。ただし、過去に、次の方法で処理を進めることにより、switch ステートメントをリファクタリングしました。多くの繰り返しコードを含む、このような switch ステートメントがあるとします。
switch(x){
case 1:
makeitso("foo");
globalLog += "foo";
case 2:
makeitso("bar");
globalLog += "bar";
case 3:
makeitso("baz");
globalLog += "baz";
...
default:
throw("input error");
}
最初に行うことは、共通する部分を認識することです (実際の世界では、これはおそらくもう少し実質的なものになるでしょう) 。
makeitso([some string]);
globalLog += [some string];
それを関数に変換します
function transformInput(somestring) {
makeitso(somestring);
globalLog += somestring;
}
次に、それぞれの場合に変化する部分については、ハッシュまたは配列を使用します。
var transformvalues = ["foo", "bar", "baz"];
ここから、次のことができます。
var tvals = ["foo", "bar", "baz" ... ];
function transformInput(somestring) {
makeitso(somestring);
globalLog += somestring;
}
var tval = tvals[x];
if(tval!==undefined) {
transformInput(tval);
} else {
throw ("invalid input");
}
また、switch ステートメントから除外された tvals を使用して、処理できるケースの数を拡張するために外部から提供することもできます。または、動的に構築することもできます。ただし、現実の世界では、多くの場合、switch ステートメントには特殊なケースがあります。それは読者の練習問題として残しておきます。
3つの提案(すでに与えられたいくつかを反映):
たぶん、スイッチはあなたが思っているほど悪くはありません。ケースブロックが大きいと見苦しくなります。ロジックをメソッドに抽出して短縮します。
オブジェクト指向言語では、多くの人が指摘しているように、ポリモーフィズムが答えかもしれません。
Javascript などの関数型言語では、入力に対して実行する必要がある関数を返す関数を記述します。これは、switch ステートメント自体を使用する場合もあれば、ルックアップ テーブルを使用する場合もあります。
いつでもルックアップ テーブルを使用できます。
switch ステートメントに 20 個のケースが含まれていても問題はありません。リファクタリングによってコードを整理し、少なくともケース処理をメソッド/関数に移動できます。
switch ステートメントが何を評価しているかによっては、ストラテジー パターンを使用してリファクタリングする必要がある場合があります。enum 値のスイッチを個別のクラスに置き換えて各関数を処理する例については、この投稿をご覧ください。
また、実際には 20 ケースでスイッチを使用することが最善の方法である可能性もあります。読みやすく、各結果がアクションの内容を明確に伝えている限り、実際にリファクタリングする必要はありません。
一般的には、機能を追加したい場合など、必要な場合にのみリファクタリングする必要があると思いますが、現在の設計では対応できません。次に、新しい機能を追加せずにリファクタリングし、その後でのみ新しい機能を追加する必要があります。
他の状況では、リファクタリングを気にしないでください。必要なときに実行してください。そうしないと、おそらくもっと重要なことがあります。
本当に必要な場合は、Visitor Design パターンが一般的なスイッチケースの代替品になりますが、欠点があることに注意してください。(つまり、 www.objectmentor.com/resources/articles/acv.pdfをチェックしてください)
switch ステートメントが何をしているかによって異なります。
パーサーなどで文字または文字列に一致し、コード内のどこでも同じパターンのセットが繰り返されていない場合は、switch ステートメントで問題ない可能性があります。
許可された値のリストに対して整数を一致させる (たとえば) 場合は、値ごとに基本クラスと一連の派生クラスを作成できます。次に、最初に整数データを生成するものはすべて、代わりにすべての switch ステートメント「応答」を使用して派生クラスのインスタンスを作成できます。
3 番目のオプションは、パターンをアクション (つまり、仮想メソッドを持つ関数またはオブジェクト) にマップするデータ構造を作成することです。このデータ構造でスイッチ値を検索し、適切なアクションを実行できます。
重大なバグなしで機能している場合 (重大ではないということは、髪を引っ張らせないということです)、わざわざリファクタリングする必要はありません。すべてをリファクタリングしないでください。
必要に応じてポリモーフィズムに変更することもできますが、これはばかげた手術になるため、おそらくこのスイッチ ブロックだけでなく、さらに多くのリファクタリングが必要になるでしょう。