圈复杂度 圈复杂度定义计算规则降低圈复杂度手段 降低圈复杂度示例修改
圈复杂度 定义
圈复杂度 (Cyclomatic complexity) 是一种代码复杂度的衡量标准,也称为条件复杂度或循环复杂度,它可以用来衡量一个模块判定结构的复杂程度,数量上表现为独立现行路径条数,也可理解为覆盖所有的可能情况最少使用的测试用例数。简称 CC 。其符号为 VG 或是 M 。
计算规则for +1; if +1; else +1; switch has n cases +n; || +1; && +1
降低圈复杂度手段1、类型判断、转换
if (visibleFlag) { visible = 1;} else { visible = 0;}改为(如:在数据库保存时无法自动转换数据类型):visible = visibleFlag + 02、独立函数调用
postTitle = postTitle ? postTitle.trim() : '';改为:postTitle = util.trim(xss.sanitize(postTitle))3、多条件合并为一个:转为数组的include等操作
if (action === 'create' || action === 'edit') {...}改为:if (['create', 'edit'].includes(action)) {...}4、空值判断简化
if (page !== undefined && page !== ''){...}改为if (!page) {...}5、嵌套if简化
if (x) { if (y) {...} else {...}} else { ...}改为:if (x && y) {...} else {...}6、复杂if改为使用正则(通配符)
if (/^1[34578]\d{9}$/i.test(phone)) {...}7、重复判断剥离并复用:赋值给变量、常量,减少二次判断
if (postStatus === 'draft' || postStatus === 'auto-draft') {...}...if (postStatus === 'draft' || postStatus === 'auto-draft') {...} else {...}改为:const postDraft = postStatus === 'draft' || postStatus === 'auto-draft';if (postDraft) {...} 降低圈复杂度示例阈值5。下面这种if判空后赋值有九处(4+5),加上两个err判断,使得原代码圈复杂度为12
func (p *Pipe) getVersionDetails(ctx *context.Context, app *asc.App, version *asc.AppStoreVersion) error { // *asc.AppInfoLocalizationResponse error 类型appLocalizationResp, err := p.Client.GetAppLocalizations(ctx, app.ID)if err != nil {return err} // Name Subtitle ... 是*string类型if appLocalizationResp.Data.Attributes.Name != nil { // AppStoreVersionDetail是model.MarketReleaseIosReq类型ctx.AppStoreVersionDetail.App = *appLocalizationResp.Data.Attributes.Namelog.Info("ctx.AppStoreVersionDetail.App:", ctx.AppStoreVersionDetail.App)}if appLocalizationResp.Data.Attributes.Subtitle != nil {ctx.AppStoreVersionDetail.SubTitle = *appLocalizationResp.Data.Attributes.Subtitlelog.Info("ctx.AppStoreVersionDetail.Subtitle:", ctx.AppStoreVersionDetail.SubTitle)} ... ...return nil} 修改 func (p *Pipe) getVersionDetails(ctx *context.Context, app *asc.App, version *asc.AppStoreVersion) error {log.Infof("getting app localizations")appLocalizationResp, err := p.Client.GetAppLocalizations(ctx, app.ID)if err != nil {return err}InitAppVersionDetailAppInfo(ctx, appLocalizationResp)...return nil}// InitAppVersionDetailAppInfo 初始化ctx.AppStoreVersionDetailfunc InitAppVersionDetailAppInfo(ctx *context.Context,appLocalizationResp *asc.AppInfoLocalizationResponse) {InitProp(ctx.AppStoreVersionDetail, "App", appLocalizationResp.Data.Attributes.Name)InitProp(ctx.AppStoreVersionDetail, "PrivacyPolicyURL", appLocalizationResp.Data.Attributes.PrivacyPolicyURL)InitProp(ctx.AppStoreVersionDetail, "Subtitle", appLocalizationResp.Data.Attributes.Subtitle)InitProp(ctx.AppStoreVersionDetail, "PrivacyPolicyText", appLocalizationResp.Data.Attributes.PrivacyPolicyText)}// 赋值功能核心// 结构体是值类型,用指针类型才会改变值。不用指针是传对象的副本,在函数外访问是没变化的。func InitProp(appStoreVersionDetail *model.MarketReleaseIosReq,ctxPropertyName string, respAttribute *string) {if respAttribute == nil {return}detail := reflect.Indirect(reflect.ValueOf(&appStoreVersionDetail)).Elem()typeOfT := detail.Type()for i := 0; i < detail.NumField(); i++ {if typeOfT.Field(i).Name == ctxPropertyName {detail.FieldByName(ctxPropertyName).Set(reflect.ValueOf(respAttribute).Elem())break}}log.Infof("ctx.AppStoreVersionDetail.%+v:%+v", ctxPropertyName, reflect.ValueOf(respAttribute).Elem())}