如何降低 returns 值取决于 3 个布尔值的笛卡尔积的函数的圈复杂度?
How can I reduce the cyclomatic complexity of a function that returns a value dependent on the cartesian product of 3 booleans?
如何降低 returns 值依赖于 3 个布尔值的笛卡尔积的函数的圈复杂度?如何让下面的代码看起来更干净?
这是一个学校项目,并不是作业本身的真正要求,但我经常发现自己编写的函数依赖于 - 有时 - 相当复杂的事实 table。我认为这不是最好的方法。
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;
}
这是一种与语言无关的范式,您会发现不同的语言会有不同的内置函数和运算符来促进对事实的处理tables。
My Favourite is the new pattern matching in C# 7.0 switch statements https://visualstudiomagazine.com/articles/2017/02/01/pattern-matching.aspx
首先,确定你的真相table
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 不依赖于优惠券条件,因此这是您的第一个优化。
要注意的第二个条件是,没有新客户是真实的并且他们有会员卡的情况,这是有道理的。
从那里开始,在代码中直观地遵循代码和编程的最简单方法是使用嵌套分支,这样我们只评估每个条件检查一次。
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;
}
使用增值可能也更容易,事实table是表示下一个代码块的好方法:
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;
}
给这只猫换皮的方法有很多 :) 上面的代码示例重点介绍了如何使用分支逻辑对每个条件仅求值一次。虽然在这种情况下微不足道,但将来评估某些条件可能会对性能产生重大影响,因此您只想评估一次。
如何降低 returns 值依赖于 3 个布尔值的笛卡尔积的函数的圈复杂度?如何让下面的代码看起来更干净?
这是一个学校项目,并不是作业本身的真正要求,但我经常发现自己编写的函数依赖于 - 有时 - 相当复杂的事实 table。我认为这不是最好的方法。
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;
}
这是一种与语言无关的范式,您会发现不同的语言会有不同的内置函数和运算符来促进对事实的处理tables。
My Favourite is the new pattern matching in C# 7.0 switch statements https://visualstudiomagazine.com/articles/2017/02/01/pattern-matching.aspx
首先,确定你的真相table
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 不依赖于优惠券条件,因此这是您的第一个优化。 要注意的第二个条件是,没有新客户是真实的并且他们有会员卡的情况,这是有道理的。 从那里开始,在代码中直观地遵循代码和编程的最简单方法是使用嵌套分支,这样我们只评估每个条件检查一次。
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;
}
使用增值可能也更容易,事实table是表示下一个代码块的好方法:
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;
}
给这只猫换皮的方法有很多 :) 上面的代码示例重点介绍了如何使用分支逻辑对每个条件仅求值一次。虽然在这种情况下微不足道,但将来评估某些条件可能会对性能产生重大影响,因此您只想评估一次。