Cómo reemplazar expresiones condicionales anidadas con guardias

 Este artículo se comparte desde la comunidad HUAWEI CLOUD " Reemplazar condiciones anidadas con cláusulas de protección", autor: JavaEdge.

motivación

Las expresiones condicionales generalmente vienen en dos sabores:

  • Ambas ramas condicionales tienen un comportamiento normal.
  • Solo una rama condicional es un comportamiento normal, la otra rama es anormal

Estos dos tipos de expresiones condicionales sirven para diferentes propósitos, que deben mostrarse en el código:

  • Si ambas ramas tienen un comportamiento normal, se debe usar una expresión condicional de la forma if...else...

  • Si una condición es extremadamente rara, debe verificarse por separado y devolverse desde la función tan pronto como la condición sea verdadera.

    Estos controles separados a menudo se denominan "cláusulas de protección".

La esencia de reemplazar expresiones condicionales anidadas con guardias es prestar especial atención a una rama. Si usa una construcción if-then-else, asigna el mismo peso a la rama if y a la rama else. El mensaje para el lector de tal estructura de código es que cada rama es igualmente importante. La declaración de guardia le dice al lector: "Esta situación no es lo que le importa a la lógica central de esta función. Si sucede, realice la limpieza necesaria y salga".

La noción de que "cada función solo puede tener una entrada y una salida" está profundamente arraigada en algunos programadores. Cuando trabajo con el código que escriben, a menudo necesito usar instrucciones de protección en lugar de expresiones condicionales anidadas. Los lenguajes de programación de hoy imponen solo una entrada por función, y la regla de "salida única" no es tan útil. Mantener el código claro es la clave: si una sola salida hace que la función sea más legible, use una sola salida; de lo contrario, no lo hace.

práctica

Seleccione la lógica condicional más externa que debe reemplazarse y reemplácela con una declaración de protección.

prueba.

Si es necesario, repita los pasos anteriores.

Si todas las sentencias de guardia producen el mismo resultado, puede combinarlas usando [Fusionar expresiones condicionales].

caso

Calcular los salarios a pagar a los empleados. Solo se debe pagar a los empleados que todavía están trabajando en la empresa, por lo que esta carta

El número debe verificar dos situaciones de "empleado que ya no está en el trabajo".

    public Long payAmount(Employee employee) {
        long result;
        if (employee.isSeparated) {
            result = 0;
        } else {
            if (employee.isRetired) {
                result = 0;
            } else {
                // logic to compute amount
                lorem.ipsum(dolor.sitAmet);
                consectetur(adipiscing).elit();
                sed.do.eiusmod = tempor.incididunt.ut(labore) && dolore(magna.aliqua);
                ut.enim.ad(minim.veniam);
                result = someFinalComputation();
            }
        } return result;
    }

La lógica condicional anidada dificulta ver lo que realmente significa el código. Solo cuando ninguna de las dos expresiones condicionales actuales es verdadera, este código realmente comienza su trabajo principal. Por lo tanto, las declaraciones de guardia permiten que el código exprese sus intenciones con mayor claridad. Como siempre, me gusta dar pequeños pasos, así que trato primero con la lógica condicional superior.

    public Long payAmount(Employee employee) {
        long result;
        if (employee.isSeparated) {
            result = 0;
        }
        if (employee.isRetired) {
            result = 0;
        } else { // logic to compute amount
            lorem.ipsum(dolor.sitAmet);
            consectetur(adipiscing).elit();
            sed.do.eiusmod = tempor.incididunt.ut(labore) && dolore(magna.aliqua);
            ut.enim.ad(minim.veniam);
            result = someFinalComputation();
        } return result;
    }

Después de hacer esta modificación, ejecuto la prueba y paso al siguiente paso.

    public Long payAmount(Employee employee) {
        long result;
        if (employee.isSeparated) {
            return 0l;
        }
        if (employee.isRetired) {
            return 0l;
        }

        lorem.ipsum(dolor.sitAmet);
        consectetur(adipiscing).elit();
        sed. do.eiusmod = tempor.incididunt.ut(labore) && dolore(magna.aliqua);
        ut.enim.ad(minim.veniam);
        result = someFinalComputation();
        return result;
    }

En este punto, la variable de resultado es inútil, así que la elimino:

    public Long payAmount(Employee employee) {
        if (employee.isSeparated) {
            return 0l;
        }
        if (employee.isRetired) {
            return 0l;
        }
        lorem.ipsum(dolor.sitAmet);
        consectetur(adipiscing).elit();
        sed. do.eiusmod = tempor.incididunt.ut(labore) && dolore(magna.aliqua);
        ut.enim.ad(minim.veniam);
        return someFinalComputation();
    }

Siempre es bueno poder reducir una variable mutable.

invertir la condición

A menudo podemos invertir la expresión condicional para reemplazar las expresiones condicionales anidadas con guardias.

public int adjustedCapital(Instrument anInstrument) {
  int result = 0;
  if (anInstrument.capital > 0) {
    if (anInstrument.interestRate > 0 && anInstrument.duration > 0) {
      result = (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor;
    }
  }
  return result;
}

Reemplace uno por uno. Pero esta vez, al insertar la declaración de guardia, necesito revertir la condición correspondiente:

public int adjustedCapital(Instrument anInstrument) {
  int result = 0;
  if (anInstrument.capital <= 0) {
    return result;
  }
  if (anInstrument.interestRate > 0 && anInstrument.duration > 0) {
    result = (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor;
  }
  return result;
}

La siguiente condición es un poco más complicada, así que hago la inversión en dos pasos. Primero agregue una operación lógica NOT:

public int adjustedCapital(Instrument anInstrument) {
  int result = 0;
  if (anInstrument.capital <= 0) {
    return result;
  }
  if (!(anInstrument.interestRate > 0 && anInstrument.duration > 0)) {
    return result;
  }
  result = (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor;
  return result;
}

Pero dejar un NO lógico en una expresión condicional como esta me arruinaría la cabeza, así que lo simplifiqué a:

public int adjustedCapital(Instrument anInstrument) {
  int result = 0;
  if (anInstrument.capital <= 0) {
    return result;
  }
  if (anInstrument.interestRate <= 0 || anInstrument.duration <= 0) {
    return result;
  }
  result = (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor;
  return result;
}

Estas dos líneas de lógica producen el mismo resultado, así que puedo combinarlas con [Fusionar expresiones condicionales]:

public int adjustedCapital(Instrument anInstrument) {
  int result = 0;
  if (anInstrument.capital <= 0 || anInstrument.interestRate <= 0 || anInstrument.duration <= 0) {
    return result;
  }
  result = (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor;
  return result;
}

En este punto, la variable de resultado hace dos cosas: primero la configuro en 0, que representa el valor de retorno cuando se activa la declaración de guardia, y luego la asigno con el resultado del cálculo final. Puedo eliminar esta variable por completo, evitar la doble responsabilidad con una variable y reducir otra variable variable.

public int adjustedCapital(Instrument anInstrument) {
  if (anInstrument.capital <= 0 || anInstrument.interestRate <= 0 || anInstrument.duration <= 0) {
    return 0;
  }
  return (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor;
}

Referirse a

  • "Reconstrucción"
  • "Arquitectura Limpia"

 
Haga clic en Seguir para conocer las nuevas tecnologías de HUAWEI CLOUD por primera vez ~

Supongo que te gusta

Origin blog.csdn.net/devcloud/article/details/124042780
Recomendado
Clasificación