ホームページ  >  記事  >  ウェブフロントエンド  >  if elseからjavascriptで大文字と小文字をabstraction_javascriptに切り替えるスキル

if elseからjavascriptで大文字と小文字をabstraction_javascriptに切り替えるスキル

WBOY
WBOYオリジナル
2016-05-16 18:23:061356ブラウズ

私の答えは、else が 2 つ以上ある場合、または case が 3 つ以上ある場合は switch です。しかし、コード内で if else を使用したり、大文字と小文字を切り替えたりするのは普通のことですよね?間違っている! 3 つ以上の分岐がある if else および switch ケースのほとんどは、ハードコーディングすべきではありません。
複雑な分岐はどこから来るのですか?
まず最初に議論したいのは、なぜ従来のコードには非常に多くの複雑な分岐が存在するのかということです。これらの複雑な分岐は、コードの最初のバージョンには存在しないことがよくあります。設計者がまだある程度の経験を持っていると仮定すると、将来拡張する必要がある領域を予測し、抽象インターフェイスを予約する必要があります。

しかし、コードが数回反復された後、特に要件の詳細を数回調整した後、複雑な分岐が表示されます。要件に対する詳細な調整は、多くの場合、UML には反映されず、コードに直接反映されます。たとえば、メッセージは当初、チャット メッセージとシステム メッセージの 2 つのカテゴリに分類されていましたが、これらは自然にメッセージ カテゴリの 2 つのサブカテゴリとして設計されました。しかし、ある日、要件が詳細に調整されることがあります。システム メッセージの一部は重要なので、そのタイトルを赤色で表示する必要があります。このとき、プログラマは、次のような変更を行うことがよくあります。
システム メッセージ クラスに重要な属性を追加します。
タイトルの色を制御するために、対応するレンダリング メソッドに重要な属性に関するブランチを追加します
プログラマはなぜそのような変更を行ったのでしょうか?おそらくそれは抽象的であるべきだと彼が気づいていなかったからでしょう。要件には「一部のシステム メッセージは重要である」と記載されているため、命令型プログラミング言語でより多くのトレーニングを受けたプログラマにとって、最初に思いつくのはフラグ ビットです。フラグ ビットは重要なものとそうでないものを区別できます。 。 重要。同氏は、この要件が「システム メッセージは 2 つのカテゴリ、重要なものと重要でないものに分類される」という別の方法で解釈される可能性があるとは予想していませんでした。このように解釈すると、システム メッセージは抽象化する必要があることがわかりました。
もちろん、プログラマは抽象化が可能であることを知っていても、何らかの理由で抽象化を行わないことを選択する可能性もあります。非常に一般的な状況は、プロジェクトの進行と引き換えにコードの品質を犠牲にすることをプログラマに強いるというものです。このフォームの変更を 10 回実行する場合、10 個のブランチを作成する方が速いですか。プロパティとブランチを追加する方がはるかに簡単です。それとも10個の抽象化ですか?違いは明らかです。
もちろん、if else が多すぎると、「switch case に変更したらどうだろう」と立ち上がる賢い人もいるでしょう。場合によっては、各ブランチが相互に排他的であると仮定すると、これによりコードの可読性が実際に向上します。しかし、スイッチケースの数が増えると、コードも読めなくなります。
複雑な分岐の欠点は何ですか
複雑な分岐の欠点は何ですか?例として、Baidu Hi Web バージョンの古いコードのセクションを取り上げます。

コードをコピー コードは次のとおりです。

switch (json.result) {
case " ok":
switch (json.command) {
case "message":
case "systemmessage":
if (json.content.from == ""
&& json.content .content == "キック") {
/* 切断 */
} else if (json.command == "systemmessage"
|| json.content.type == "sysmsg" ) {
/* システム メッセージをレンダリングします */
} else {
/* チャット メッセージをレンダリングします */
}
break;


このコードは理解するのが難しくないので、簡単な質問をします。次の JSON ヒットを実行するブランチは次のとおりです:


{
"result": "ok",
"command": "message",
"content": {
"from" : "CatChen",
"content": "Hello!"
}
}


この JSON ヒットは簡単に正解できます。 /* チャット メッセージをレンダリング */ (チャット メッセージを表示) このブランチ。それで、どうやってこの判断を下したのか知りたいのですが?まず、case "ok": ブランチにヒットするかどうかを確認し、結果がヒットするかどうかを確認する必要があります。次に、case "message": ブランチにヒットするかどうかを確認し、結果もヒットするかどうかを確認する必要があります。 case "system message" を確認する必要はありません。 ; 次に、if の条件にもヒットせず、else if の条件にもヒットしないため、else 分岐にヒットします。
問題がわかりましたか?なぜ他の部分を見て、この JSON がこのブランチにヒットすると言えないのでしょうか? else 自体には条件が含まれていないため、条件を意味するだけです。それぞれの else の条件は、その前の if と else if の否定とその後の AND 演算の結果です。言い換えれば、この else のヒットを判断することは、ヒットを判断するための複雑な条件セットと同等です:


コピー コードコードは次のとおりです:

!(json.content.from == "" && json.content.content == "キック") && !(json.command == "systemmessage" || json.content.type == " sysmsg")

外側の 2 つのスイッチ ケースをオンにします。この分岐の条件は次のとおりです:
コードをコピー コードは次のとおりです:

json.result == "ok" && (json.command == "message" || json.command == "systemmessage") && !(json.content.from == "" && json.content.content == "キック") && !(json.command == "systemmessage" || json.content.type == "sysmsg")

ここに繰り返しのロジックがあります。省略すると、次のようになります。
コードをコピー コードは次のとおりです。次のように:

json.result == "ok" && json.command == "message" && !(json.content.from == "" && json.content.content == "キック") && ! (json.content.type == "sysmsg")

単純な 4 文字の else からこのような長い一連の論理演算式を導き出すのに、どれだけの労力を費やしたでしょうか?しかも、この表現はよく見ないと何を言っているのか分かりません。
ここで、複雑なブランチの読み取りと管理が困難になります。 if else を含む switch ケースに直面していると想像してください。合計 3 つのケースがあり、それぞれのケースに 3 つの else があり、各分岐とその前提条件がすべて含まれています。すべての祖先分岐は非 then-AND の結果です。
複雑な分岐を避ける方法
まず第一に、複雑な論理演算を避けることはできません。リファクタリングの結果は同等のロジックになるはずです。私たちにできることは、コードを読みやすく、管理しやすくすることだけです。したがって、複雑な論理演算を読みやすく管理しやすくする方法に焦点を当てる必要があります。
クラスまたはファクトリーへの抽象化
オブジェクト指向設計に慣れている人にとって、これは複雑な論理演算を分割し、それらを異なるクラスに分散することを意味するかもしれません:
コードをコピー コードは次のとおりです:

switch (json.result) {
case "ok":
var Factory = commandFactories .getFactory(json.command);
var command = Factory.buildCommand(json);
break;


少なくともブランチが短くなり、コードが読みやすくなりました。このスイッチケースはステータスコード分岐のみを処理します。「ok」ステータスコードをどのように扱うかは他のクラスの問題です。 getFactory 内には、この命令がどのファクトリを選択するかの選択を作成することに重点を置いた一連の分岐がある場合があります。同時に、buildCommand には、この命令の構築方法を決定する他の簡単な分岐がある場合があります。
この利点は、ブランチ間の入れ子関係が解消され、各ブランチが独自のコンテキスト内でのみ正しい状態を維持する必要があることです。たとえば、getFactory は名前付き関数になりました。そのため、この関数内の分岐は、getFactory が実際に呼び出されるコンテキストに注意を払うことなく、getFactory という名前によって暗示されるコントラクトを実装するだけで済みます。
抽象をパターン マッチングに変換します
もう 1 つの方法は、この複雑な論理演算をパターン マッチングに変換することです:


Network.listen({
"result": "ok",
"command": "message",
"content": { " from": "", "content": "kicked" }
}, function(json) { /* 切断 */ });
Network.listen([{
"result": " ok ",
"command": "message",
"content": { "type": "sysmsg" }
}, {
"result": "ok",
" command": "systemmessage"
}], function(json) { /* システム メッセージをレンダリング */ });
Network.listen({
"result": "ok",
" command": "message",
"content": { "from$ne": "", "type$ne": "sysmsg" }
}, function tion(json) { /* チャットメッセージをレンダリングする*/ });


Is it much clearer now? The first case is to be kicked offline and must match the specified from and content values. The second case is to display system messages. Since the system messages are slightly different in the two versions of the protocol, we need to capture two different JSONs, and any one that matches is considered a hit. The third situation is to display chat messages. Since system messages and kick-off instructions are special chat messages in the old version of the protocol, in order to be compatible with the old version of the protocol, these two situations must be excluded from the display of chat messages, so Just use the suffix "$ne" (meaning not equal) for matching.
Since the listen method is context-free, each listen independently declares what kind of JSON it matches, so there is no implicit logic. For example, to capture chat messages, you must explicitly exclude from == "" and type == "sysmsg", which does not need to be inferred from the context if else.
Using pattern matching, you can greatly improve the readability and maintainability of your code. Since what we want to capture is JSON, we use JSON to describe what each branch wants to capture, which is much clearer than a long logical operation expression. At the same time, every modification on this JSON is independent, and modifying one condition does not affect other conditions.
Finally, how to write such a pattern matching module is beyond the scope of this article.
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。