これは、美しいコードの章に関連しています。そしてその章で私はネストされたif
sについて読みました。
if
作者は、バグの発生源であり、読みにくいものとして、深くネストされたsについて話していました。そして、彼はネストされたif
sをcase
ステートメントとデシジョンテーブルに置き換えることについて話していました。
if
ネストされたsをcase
(select case
)とデシジョンテーブルで削除する方法を誰かが説明できますか?
これは、美しいコードの章に関連しています。そしてその章で私はネストされたif
sについて読みました。
if
作者は、バグの発生源であり、読みにくいものとして、深くネストされたsについて話していました。そして、彼はネストされたif
sをcase
ステートメントとデシジョンテーブルに置き換えることについて話していました。
if
ネストされたsをcase
(select case
)とデシジョンテーブルで削除する方法を誰かが説明できますか?
スイッチ/ケースステートメントについて具体的に質問しているため、質問への直接の回答ではありませんが、同様の質問があります。
これは、ネストされた if を、戻り値に落ち着く前により多くのことを徐々にチェックするのではなく、早期に戻るガード ステートメントに置き換えることについて述べています。
私がいつもやろうとしている1つの例は、このようにネストされたものを置き換えることです(実際、これはそれほど悪くはありませんが、野生では8または9レベルまで見たことがあります)。
if (i == 1) {
// action 1
} else {
if (i == 2) {
// action 2
} else {
if (i == 3) {
// action 3
} else {
// action 4
}
}
}
これとともに:
switch (i) {
case 1:
// action 1
break;
case 2:
// action 2
break;
case 3:
// action 3
break;
default:
// action 4
break;
}
また、アクションをできるだけ小さくして(これには関数呼び出しが最適です)、switchステートメントを圧縮したままにします(したがって、4ページ先に進んでその終わりを確認する必要はありません)。
デシジョンテーブルは、後で実行する必要のあるアクションを示すフラグを設定しているだけだと思います。「後で」セクションは、これらのフラグに基づくアクションの単純な順序付けです。私は間違っている可能性があります(それは最初でも最後でもありません:-)。
例は次のようになります(そのアクションが非常に単純であるため、フラグ設定フェーズは複雑になる可能性があります):
switch (i) {
case 1:
outmsg = "no paper";
genmsg = true;
mailmsg = true;
phonemsg = false;
break;
case 2:
outmsg = "no ink";
genmsg = true;
mailmsg = true;
phonemsg = false;
break;
default:
outmsg = "unknown problem";
genmsg = true;
mailmsg = true;
phonemsg = true;
break;
}
if (genmsg)
// Send message to screen.
if (mailmsg)
// Send message to operators email address.
if (phonemsg)
// Hassle operators mobile phone.
連鎖したifはどうですか?
交換
if (condition1)
{
do1
}
else
{
if (condition2)
{
do2
}
else (condition3)
{
do3;
}
}
と
if (condition1) {
do1;
} else if (condition2) {
do2;
} else if (condition3) {
do3;
}
これは、複雑な条件のswitchステートメントによく似ています。
条件をブール値にしてから、それぞれの場合にブール式を記述します。
コードが次の場合:
if (condition1)
{
do1
}
else
{
if (condition2)
{
do2
}
else (condition3)
{
do3;
}
}
次のように書くことができます:
bool cond1=condition1;
bool cond2=condition2;
bool cond3=condition3;
if (cond1) {do1;}
if (!cond1 and cond2) {do2;}
if (!cond1 and cond3) {do2;}
デシジョン テーブルについては、この質問に対する私の回答を参照するか、 Code Complete 2の第 18 章をお読みください。
デシジョンテーブルは、コード自体ではなく、データ構造に条件付きロジックを格納する場所です。
したがって、これの代わりに(@Paxの例を使用して):
if (i == 1) {
// action 1
} else {
if (i == 2) {
// action 2
} else {
if (i == 3) {
// action 3
} else {
// action 4
}
}
}
あなたはこのようなことをします:
void action1()
{
// action 1
}
void action2()
{
// action 2
}
void action3()
{
// action 3
}
void action4()
{
// action 4
}
#define NUM_ACTIONS 4
// Create array of function pointers for each allowed value of i
void (*actions[NUM_ACTIONS])() = { NULL, action1, action2, action3 }
// And now in the body of a function somewhere...
if ((i < NUM_ACTIONS) && actions[i])
actions[i]();
else
action4();
の可能性i
が小さい整数でない場合は、配列のi
th要素に直接アクセスする代わりにルックアップテーブルを作成できます。actions
この手法は、数十の可能な値を決定する場合に、ネストされたif
sまたはステートメントよりもはるかに便利になります。switch
また、 Visitorパターンの使用を検討することもできます。
if ステートメントと switch ステートメントは、純粋に OO ではありません。それらは条件付きの手続き型ロジックですが、非常にうまく機能します。OO アプローチを強化するためにこれらのステートメントを削除する場合は、「状態」パターンと「記述子」パターンを組み合わせます。
ネストされた if は、論理演算子 AND と同等です
if (condition1)
{
if (function(2))
{
if (condition3)
{
// do something
}
}
}
同等のコード:
if (condition1 && function(2) && condition3)
{
// do something
}
どちらの場合も、式が false と評価されると、後続の式は評価されません。たとえば、condition1 が false の場合、function() は呼び出されず、condition3 は評価されません。
一部の言語で許可されている別の例はこれです
switch true{
case i==0
//action
break
case j==2
//action
break
case i>j
//action
break
}