21

私自身と同僚は、次のうちどちらがよりエレガントかについて論争しています。誰とは言いませんので、中立です。どちらがエレガントですか?

public function set hitZone(target:DisplayObject):void
        {
            if(_hitZone != target)
            {
                _hitZone.removeEventListener(MouseEvent.ROLL_OVER, onBtOver);
                _hitZone.removeEventListener(MouseEvent.ROLL_OUT, onBtOut);
                _hitZone.removeEventListener(MouseEvent.MOUSE_DOWN, onBtDown);

                _hitZone = target;

                _hitZone.addEventListener(MouseEvent.ROLL_OVER, onBtOver, false, 0, true);
                _hitZone.addEventListener(MouseEvent.ROLL_OUT, onBtOut, false, 0, true);
                _hitZone.addEventListener(MouseEvent.MOUSE_DOWN, onBtDown, false, 0, true);
            }
        }

...また...

public function set hitZone(target:DisplayObject):void
        {
            if(_hitZone == target)return;

            _hitZone.removeEventListener(MouseEvent.ROLL_OVER, onBtOver);
            _hitZone.removeEventListener(MouseEvent.ROLL_OUT, onBtOut);
            _hitZone.removeEventListener(MouseEvent.MOUSE_DOWN, onBtDown);

            _hitZone = target;

            _hitZone.addEventListener(MouseEvent.ROLL_OVER, onBtOver, false, 0, true);
            _hitZone.addEventListener(MouseEvent.ROLL_OUT, onBtOut, false, 0, true);
            _hitZone.addEventListener(MouseEvent.MOUSE_DOWN, onBtDown, false, 0, true);

        }
4

14 に答える 14

44

ほとんどの場合、早期に戻ることで複雑さが軽減され、コードが読みやすくなります。

これは、スパルタン プログラミングで適用される手法の 1 つでもあります。

コントロールの最小限の使用

  1. 三値化、継承、および Class Defaults、Class Once、Class Separator などのクラスなどの特殊な構造を使用して、条件の使用を最小限に抑える
  2. Early で条件を単純化しますreturn
  3. Class Separate や Class FileSystemVisitor などのアクション アプリケータ クラスを使用して、ループ コンストラクトの使用を最小限に抑えます。
  4. 早期終了による反復のロジックの簡素化 ( returncontinue およびbreakステートメントによる)。

あなたの例では、コードが読みやすくなるため、オプション 2 を選択します。関数のパラメーターをチェックするときも同じ手法を使用します。

于 2008-12-10T10:58:54.023 に答える
21

これは、規則 (つまり、ベスト プラクティス) を破ってもよいケースの 1 つです。一般に、関数内の戻り点はできるだけ少なくする必要があります。これの実際的な理由は、すべての関数が引数を取り、そのロジックを実行し、その結果を返すと常に想定できるため、コードの読み取りが簡単になることです。さまざまなケースに対して余分なリターンを入れると、ロジックが複雑になり、コードを読んで完全に理解するのに必要な時間が長くなる傾向があります。コードがメンテナンス段階に達すると、新しいプログラマーがロジックを解読しようとするため、複数のリターンが生産性に大きな影響を与える可能性があります (コメントがまばらでコードが不明確な場合は特に悪いことです)。問題は、関数の長さに関して指数関数的に大きくなります。

では、なぜこの場合、誰もがオプション 2 を好むのでしょうか? これは、関数が受信データまたはチェックする必要がある可能性のあるその他の不変条件を検証することによって強制するコントラクトを設定しているためです。検証を構築するための最も美しい構文は、各条件をチェックし、条件が有効でない場合はすぐに戻ることです。そうすれば、すべてのチェックで何らかの isValid ブール値を維持する必要がなくなります。

要約すると、一般的なロジックではなく、検証コードの書き方を実際に検討しています。オプション 2 は検証コードに適しています。

于 2008-12-10T12:11:07.137 に答える
11

初期リターンが関数/メソッド本体の上部にあるブロックとして編成されている限り、別のネスト層を追加するよりもはるかに読みやすいと思います。

体の途中での早期復帰は極力避けるようにしています。それが最善の方法である場合もありますが、ほとんどの場合、それらは複雑になると思います。

また、原則として、制御構造の入れ子を最小限に抑えるようにしています。明らかに、これは行き過ぎになる可能性があるため、ある程度の裁量を使用する必要があります。ネストされたifを単一のスイッチ/ケースに変換することは、述語がいくつかの部分式を繰り返す場合でも、私にははるかに明確です(そして、これが部分式の削除を行うにはあまりにも愚かな言語のパフォーマンスクリティカルなループではないと仮定します)。特に、長い関数/メソッド本体でネストされた if の組み合わせは嫌いです。なぜなら、何らかの理由でコードの途中にジャンプすると、特定の行のコンテキストを精神的に再構築するために上下にスクロールすることになるからです。

于 2008-12-10T11:09:49.837 に答える
4

私の経験では、プロジェクトで早期返品を使用する際の問題は、プロジェクトの他のメンバーがそれに慣れていない場合、それらを探そうとしないことです。そのため、早期に復帰するかどうかに関係なく、複数のプログラマーが関与している場合は、全員が少なくとも彼らの存在を認識していることを確認してください。

戻りを遅らせると、多くのネストされたループや条件を安全に終了しようとするなど、余分な複雑さが生じることが多いため、私は個人的にできるだけ早く戻るようにコードを書きます。

そのため、なじみのない関数を調べるとき、最初に行うことはすべてのreturns を探すことです。本当に役立つのは、構文の色分けを設定してreturn、他の色とは異なる色を与えることです。(私は赤を選びます。) そうreturnすれば、 s は、不注意な人の隠れた障害ではなく、関数が何をするかを決定するための便利なツールになります。

于 2008-12-10T11:48:52.330 に答える
1

前に述べたように、早期復帰はより読みやすく、特に関数の本体が長い場合、3 ページの関数で誤って } を削除して (それ自体はあまりエレガントではありません)、コンパイルしようとすると時間がかかることがあります。数分間の自動化不可能なデバッグ。

また、コードをより宣言的にします。これは、別の人に説明する方法であるため、おそらく開発者はそれを理解するのに十分近いでしょう。

後で関数の複雑さが増し、適切なテストがある場合は、各代替案を新しい関数でラップし、ケース分岐で呼び出すだけで、宣言的なスタイルを維持できます。

于 2008-12-10T11:40:17.433 に答える
1

あぁ守護神。

私見、はい-戻り値が明示的で条件のすぐ隣にあり、同様の構造でうまくグループ化できるため、そのロジックはより明確です。これは、「return」が「throw new Exception」に置き換えられた場合にさらに当てはまります。

于 2008-12-10T11:03:38.133 に答える
0

良い答えがある入れ子を減らすための「if」ステートメントの反転を含む、いくつかの同様のスレッドをすでに見たので、私はそれを正確な複製として閉じたいと思います。

とりあえずライブにします...^_ ^

その答えを出すために、私は、ガード句としての早期復帰は、深くネストされたifよりも優れていると信じています。

于 2008-12-10T12:43:31.597 に答える
0

他に少なくとも 1 つの選択肢があります。実際の作業の詳細を、作業を実行するかどうかの決定から切り離します。次のようなもの:

public function setHitZone(target:DisplayObject):void
    {
        if(_hitZone != target)
            setHitZoneUnconditionally(target);

    }

public function setHitZoneUnconditionally(target:DisplayObject):void
    {
        _hitZone.removeEventListener(MouseEvent.ROLL_OVER, onBtOver);
        _hitZone.removeEventListener(MouseEvent.ROLL_OUT, onBtOut);
        _hitZone.removeEventListener(MouseEvent.MOUSE_DOWN, onBtDown);

        _hitZone = target;

        _hitZone.addEventListener(MouseEvent.ROLL_OVER, onBtOver, false, 0, true);
        _hitZone.addEventListener(MouseEvent.ROLL_OUT, onBtOut, false, 0, true);
        _hitZone.addEventListener(MouseEvent.MOUSE_DOWN, onBtDown, false, 0, true);

    }

これら 3 つのいずれか (2 つと上記の 3 つ目) は、このような小さなケースでは妥当です。しかし、何百行もの長さの関数に複数の「救済ポイント」が散りばめられているのは悪いことです。

于 2008-12-11T01:03:22.557 に答える
0

私は、関数の先頭ですぐに戻ることを避け、可能な限り、メソッドが呼び出される前にメソッドに入るのを防ぐ修飾ロジックを配置することを好みます。もちろん、これはメソッドの目的によって異なります。

ただし、メソッドが短く読みやすいものであれば、メソッドの途中で戻ってもかまいません。メソッドが大きい場合、私の意見では、メソッドはまだあまり読みやすくないため、インライン リターンを使用して複数の関数にリファクタリングするか、最後に 1 つのリターンを使用して制御構造から明示的に切り離します。

于 2008-12-10T12:04:12.207 に答える
0

オプション 1 の方が優れています。これは、プロシージャ内のリターン ポイントの数を最小限に抑える必要があるためです。などの例外があります

  もし) {
    x を返します。
  }
  y を返します。

これは言語の仕組みによるものですが、一般的には、出口点を可能な限り少なくする方がよいでしょう。

于 2008-12-10T11:29:25.630 に答える
0

この場合 (1 つのテスト、else 句なし)、テスト アンド リターンが気に入っています。その場合、関数の残りを読み取る必要がなければ、何もする必要がないことが明らかになります。

ただし、これは極細の毛を分割しています。私はあなたが心配するより大きな問題を抱えているに違いないと確信しています:)

于 2008-12-10T11:01:04.220 に答える
0

オプション 2 の方が読みやすいですが、else を追加する必要がある場合は、コードの管理性が低下します。

したがって、確信がある場合は、オプション 2 に他に行くことはありませんが、else 条件の範囲がある場合は、オプション 1 をお勧めします。

于 2008-12-10T11:05:09.533 に答える
0

私は両方のタイプのコードを見てきましたが、私にとっては読みやすく理解しやすいように見える最初のコードを好みますが、初期に存在する方が良い方法であるという多くの場所を読みました。

于 2008-12-10T13:06:09.290 に答える