[Language-agnostic] 거대한 조건을 어떻게 처리합니까?


Answers

나는 아무도 이것을 아직 얻지 못한 것에 놀랐다. 이러한 유형의 문제에 대한 리팩토링이 특별히 있습니다.

http://www.refactoring.com/catalog/decomposeConditional.html

Question

그것은 제가 사용해온 모든 언어에서 저를 괴롭혔습니다. if 문을 가지고 있지만 조건부 부분이 여러 줄로 나뉘어져 있고, if 문을 중첩하여 사용하거나 그냥 추한 것을 받아 들여야합니다. 내 인생과.

저와 다른 사람들이 같은 문제를 겪었다는 것을 당신이 발견 한 다른 방법이 있습니까?

예, 한 줄에 모두 :

if (var1 = true && var2 = true && var2 = true && var3 = true && var4 = true && var5 = true && var6 = true)
{

멀티 라인 예 :

if (var1 = true && var2 = true && var2 = true
 && var3 = true && var4 = true && var5 = true
 && var6 = true)
{

예 - 중첩 :

if (var1 = true && var2 = true && var2 = true && var3 = true)
{
     if (var4 = true && var5 = true && var6 = true)
     {



Perl에서이 작업을 수행했다면이 방법을 사용하여 검사를 수행 할 수 있습니다.

{
  last unless $var1;
  last unless $var2;
  last unless $var3;
  last unless $var4;
  last unless $var5;
  last unless $var6;

  ... # Place Code Here
}

서브 루틴을 통해 이것을 사용하려는 경우 return 의 모든 인스턴스를 return 대체하십시오.




    if (   (condition_A)
        && (condition_B)
        && (condition_C)
        && (condition_D)
        && (condition_E)
        && (condition_F)
       )
    {
       ...
    }

반대로

    if (condition_A) {
       if (condition_B) {
          if (condition_C) {
             if (condition_D) {
                if (condition_E) {
                   if (condition_F) {
                      ...
                   }
                }
             }
          }
       }
    }

    if (   (   (condition_A)
            && (condition_B)
           )
        || (   (condition_C)
            && (condition_D)
           )
        || (   (condition_E)
            && (condition_F)
           )
       )
    {
       do_this_same_thing();
    }

반대로

    if (condition_A && condition_B) {
       do_this_same_thing();
    }
    if (condition_C && (condition_D) {
       do_this_same_thing();
    }
    if (condition_E && condition_F) {
       do_this_same_thing();
    }

연산자 우선 순위 규칙에 의존하지 않고 괄호 수가 적은 경우 여러 조건부식이 명시 적 괄호를 사용하여 식 분석을 지시하지 않으면 코드를 검사하는 대부분의 정적 분석 도구가 불만을 제기합니다.

동일한 들여 쓰기 수준의 동일한 들여 쓰기 수준에서 동일한 수직 들여 쓰기 (왼쪽 / 오른쪽 괄호 ()), 괄호가있는 조건부 표현식 및 연산자는 매우 유용한 연습으로, 모든 것을 방해하지 않고 코드의 가독성과 명확성을 크게 향상시킵니다. 한 줄에 끼어 있거나 수직 정렬, 공백 또는 괄호를 사용할 수 없습니다.

연산자 우선 순위 규칙은 까다 롭습니다. 예를 들어, &&는 ||보다 우선 순위가 높지만 | &&보다 우선 함

그래서 ...

    if (expr_A & expr_B || expr_C | expr_D & expr_E || expr_E && expr_F & expr_G || expr_H {
    }

단순한 인간이 부적절하게 읽고 평가할 수있는 여러 조건부 표현이 정말 쉽습니다.

    if (   (  (expr_A)
            & (expr_B)
           )
        || (  (expr_C)
            | (  (expr_D)
               & (expr_E)
              )
           )
        || (   (expr_E)
            && (  (expr_F)
                & (expr_G)
               )
           )
        || (expr_H)
       )
    {
    }

가로 공간 (줄 바꿈), 세로 맞춤 또는 명시 적 괄호 유도 식 평가에 아무런 문제가 없습니다.이 모든 것이 읽기 쉽고 명확합니다.




@tweakt

그것은 더 낫지 않지만 과거에 내가 한 일은 다음과 같습니다.

부울 ok = cond1; ok & = cond2; ok & = cond3; ok & = cond4; ok & = cond5; ok & = cond6;

다음과 같은 :

확인 = (cond1 && cond2 && cond3 && cond4 && cond5 && cond6);

사실,이 두 가지는 대부분의 언어에서 동일하지 않습니다. 두 번째 표현식은 조건 중 하나가 거짓이면 즉시 평가가 중단되며, 조건을 평가하는 것이 비용이 많이들 경우 성능이 크게 향상 될 수 있습니다.

가독성을 위해 필자는 위의 Mike Stone의 제안을 개인적으로 선호합니다. 조기에 해낼 수 있다는 계산상의 이점을 자세히 설명하고 보존하는 것은 쉽습니다. 조건부 평가를 다른 기능에서 멀리 이동시키기 위해 코드 구성을 혼동하는 경우에도 동일한 기술을 인라인으로 수행 할 수 있습니다. 약간 치즈 맛이 있지만 항상 다음과 같이 할 수 있습니다.

do {
    if (!cond1)
       break;
    if (!cond2)
       break;
    if (!cond3)
       break;
    ...
    DoSomething();
} while (false);

while (거짓)은 일종의 치즈 냄새입니다. 언어가 "한 번"또는 쉽게 벗어날 수있는 범위 지정 연산자를 사용하길 바랍니다.




나는 이것을 종종 부울 변수로 나눌 것이다.

bool orderValid = orderDate < DateTime.Now && orderStatus != Status.Canceled;
bool custValid = customerBalance == 0 && customerName != "Mike";
if (orderValid && custValid)
{
...



먼저 모든 부품을 제거하면 == true 50 % 더 짧아집니다.)

큰 조건이있을 때 나는 이유를 찾는다. 때로는 다형성을 사용해야하는 경우가 있는데 때로는 일부 상태 객체를 추가해야합니다. 기본적으로 리팩토링이 필요함을 의미합니다 (코드 냄새).

때로는 부울 표현식을 단순화하기 위해 De-Morgan의 법칙 을 사용합니다.




파이썬으로 프로그래밍을한다면, 내장 된 all() 함수를 변수 목록에 적용하여 간단하게 처리 할 수 ​​있습니다 (여기서 부울 리터럴 만 사용하게 될 것입니다).

>>> L = [True, True, True, False, True]
>>> all(L) # True, only if all elements of L are True.
False
>>> any(L) # True, if any elements of L are True.
True

귀하의 언어로 해당 기능이 있습니까 (C #? Java?). 그렇다면 아마도 가장 깨끗한 접근법 일 것입니다.




코드 완성 에서 Steve Mcconell의 조언 : 다차원 테이블을 사용하십시오. 각 변수는 테이블에 대한 인덱스 역할을하며 if 문은 테이블 조회로 바뀝니다. 예를 들어, (size == 3 && weight> 70)이 테이블 항목 결정 [size] [weight_group]




PHP와 같은 반사 언어에서는 변수 변수를 사용할 수 있습니다.

$vars = array('var1', 'var2', ... etc.);
foreach ($vars as $v)
    if ($$v == true) {
        // do something
        break;
    }



글쎄, 먼저, 왜 안 :

if (var1 && var2 && var2 && var3 && var4 && var5 && var6) {
...

또한 추상 코드 예제를 리팩토링하는 것은 매우 어렵습니다. 구체적인 예를 보여 주면 문제에 더 잘 맞는 패턴을 쉽게 식별 할 수 있습니다.

더 나은 것은 아니지만 과거에 해왔 던 작업은 다음과 같습니다 (다음 방법은 부울 테스트의 단락을 방지합니다. 첫 번째 테스트가 false 인 경우에도 모든 테스트가 실행됩니다.) 코드를 반환하기 전에 - 내 실수를 발견하기위한 ptomato에 감사드립니다!)

부울 ok = cond1;
ok & = cond2;
ok & = cond3;
ok & = cond4;
ok & = cond5;
ok & = cond6;

어느 것이 같은 것인가 : (동일하지 않음, 상기 참고!)

확인 = (cond1 && cond2 && cond3 && cond4 && cond5 && cond6);