您好,欢迎来到外链网!
当前位置:外链网 » 站长资讯 » 专业问答 » 文章详细 订阅RssFeed

降低圈复杂度的方法,如何降低圈复杂度

来源:互联网 浏览:76次 时间:2023-04-08

圈复杂度 圈复杂度定义计算规则降低圈复杂度手段 降低圈复杂度示例修改

圈复杂度 定义

圈复杂度 (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 + 0

2、独立函数调用

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())}