php - 如何降低返回值取决于 3 个 bool 值的笛卡尔积的函数的圈复杂度?

标签 php cyclomatic-complexity

如何降低返回值取决于 3 个 bool 值的笛卡尔积的函数的圈复杂度?如何让下面的代码看起来更干净?

这是一个学校项目,并不是作业本身的要求,但我通常发现自己编写的函数依赖于(有时)相当复杂的真值表。我认为这不是最好的方法。

    public function getDiscount( $values ) {

    $res       = new stdClass();
    $res->code = 400;

    if ( ! is_bool( $values['new_customer'] ) || ! is_bool( $values['loyalty_card'] ) || ! is_bool( $values['coupon'] ) ) {
        $res->data = "Missing inputs";

        return $res;
    }

    if ( $values['new_customer'] == true && $values['loyalty_card'] == true && $values['coupon'] == true ) {
        $res->data = "Invalid input";

        return $res;
    }

    if ( $values['new_customer'] == true && $values['loyalty_card'] == true && $values['coupon'] == false ) {
        $res->data = "Invalid input";

        return $res;
    }

    $res->code = 200;

    if ( $values['new_customer'] == true && $values['loyalty_card'] == false && $values['coupon'] == true ) {
        $res->data = 20;

        return $res;
    }

    if ( $values['new_customer'] == true && $values['loyalty_card'] == false && $values['coupon'] == false ) {
        $res->data = 15;

        return $res;
    }

    if ( $values['new_customer'] == false && $values['loyalty_card'] == true && $values['coupon'] == true ) {
        $res->data = 30;

        return $res;
    }

    if ( $values['new_customer'] == false && $values['loyalty_card'] == true && $values['coupon'] == false ) {
        $res->data = 10;

        return $res;
    }

    if ( $values['new_customer'] == false && $values['loyalty_card'] == false && $values['coupon'] == true ) {
        $res->data = 20;

        return $res;
    }

    if ( $values['new_customer'] == false && $values['loyalty_card'] == false && $values['coupon'] == false ) {
        $res->data = 0;

        return $res;
    }

    $res->code = 400;
    $res->data = "Invalid input";
    return $res;

}

最佳答案

这是一种与语言无关的范例,您会发现不同的语言将具有不同的内置函数和运算符来促进真值表的处理。

My Favourite is the new pattern matching in C# 7.0 switch statements https://visualstudiomagazine.com/articles/2017/02/01/pattern-matching.aspx

首先,确定你的真值表

CASE    New Customer    Loyalty     Coupon  Output
  1        Yes            Yes        Yes    'Invalid Input'
  2        Yes            Yes        No     'Invalid Input'             
  3        Yes            No         Yes      20
  4        Yes            No         No       15                
  5        No             Yes        Yes      30
  6        No             Yes        No       10                
  7        No             No         Yes      20
  8        No             No         No       0             

我们立即可以看到情况 1 和 2 不依赖于优惠券条件,因此这是您的第一个优化。 第二个需要注意的条件是,没有新客户是真实的并且他们拥有成员(member)卡的情况,这是有道理的。 从那里开始,在代码中直观地遵循和编程的最简单方法是使用嵌套分支,这样我们只评估每个条件检查一次。

public function getDiscount( $values ) {

    $res       = new stdClass();
    $res->code = 400;

    if ( ! is_bool( $values['new_customer'] ) || ! is_bool( $values['loyalty_card'] ) || ! is_bool( $values['coupon'] ) ) {
        $res->data = "Missing inputs";

        return $res;
    }

    if ( $values['new_customer'] == true && $values['loyalty_card'] == true ) {
        $res->data = "Invalid input";

        return $res;
    }

    $res->code = 200;

    // Check New Customer conditions
    if ( $values['new_customer'] == true) {
        if( $values['coupon'] == true ) 
            $res->data = 20;
        else
            $res->data = 15;
    }

    // Check existing customer conditions
    else {

        // Has Loyalty Card
        if ( $values['loyalty_card'] == true ) {
            // Has Coupon
            if( $values['coupon'] == true ) 
                $res->data = 30;
            else
                $res->data = 10;
        }

        // No Loyalty Card
        else {
            // Has Coupon
            if( $values['coupon'] == true ) 
                $res->data = 20;
            else
                $res->data = 0;
        }
    }

    // Don't need a default fail condition here, because we have covered all possible combinations     
    return $res;

}

使用值加法可能也更容易,真值表是表示下一个代码块的好方法:

CASE    New Customer    Loyalty     Coupon  Output
  1        Yes            Yes        Yes    'Invalid Input'
  2        Yes            Yes        No     'Invalid Input'             
  3        Yes  +15       No         Yes +5   =20
  4        Yes  +15       No         No       =15               
  5        No             Yes +10    Yes +20  =30
  6        No             Yes +10    No       =10               
  7        No             No         Yes +20  =20
  8        No             No         No       0             

public function getDiscount( $values ) {

    $res       = new stdClass();
    $res->code = 400;

    if ( ! is_bool( $values['new_customer'] ) || ! is_bool( $values['loyalty_card'] ) || ! is_bool( $values['coupon'] ) ) {
        $res->data = "Missing inputs";

        return $res;
    }

    if ( $values['new_customer'] == true && $values['loyalty_card'] == true ) {
        $res->data = "Invalid input";

        return $res;
    }

    $res->code = 200;
    $res->data = 0;

    // Check New Customer conditions
    if ( $values['new_customer'] == true) {
        $res->data += 15;
        if( $values['coupon'] == true ) 
            $res->data += 5;
    }

    // Check existing customer conditions
    else {

        // Has Loyalty Card
        if ( $values['loyalty_card'] == true )
            $res->data += 10;

        // Has Coupon
        if( $values['coupon'] == true ) 
            $res->data += 20;
    }

    // Don't need a default fail condition here, because we have covered all possible combinations     
    return $res;

}

有很多方法可以给这只猫剥皮:) 上面的代码示例重点介绍了如何使用分支逻辑仅对每个条件求值一次。虽然在这种情况下微不足道,但将来评估某些条件可能会对性能产生重大影响,因此您只想评估一次。

关于php - 如何降低返回值取决于 3 个 bool 值的笛卡尔积的函数的圈复杂度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42911513/

相关文章:

php - SQL/Joomla 数据库查询 - 伪代码需要翻译

javascript - 如何在提交表单后显示下拉菜单过滤器选定的值?

php - 在 PHPUnit 中实现给定接口(interface)的模拟对象上的未定义方法?

php - "join"函数上的 MySQL 数学

private - 通过使用私有(private)方法正确地降低了圈复杂度?

angularjs - Angular 应用程序的最大圈复杂度

java - 降低java方法的圈复杂度

java圈复杂度工具使用完全限定的类名

php - 需要性能良好的SQL查询才能选择不符合条件的数据

后续过程的控制流图和圈复杂度