一、方法概述
->提取函数(Extract Method)
将重复的代码提取出来成为单独的函数。
->分解条件(Decompose Conditional)
从判断分支中分别提取出独立函数。
->合并条件表达式(Consolidate Conditional Expression)
将多个判断条件合并成一个函数。
->合并重复的条件片段(Consolidate Duplicate Conditional Fragments)
如果每个判断分支都有同一段代码,将重复的代码移到条件判断之外。
->移除控制标记(Remove Control Flag)
以break语句或return语句取代控制标记。
->表格驱动(Table drive)
通过表格消除条件判断。
二、示例代码
示例代码的圈复杂度为20。
这个程序的功能是计算并打印出给定日期(年、月、日)是星期几。它基于一个已知的事实:1990年1月1日是星期一。程序通过计算从1990年1月1日到给定日期之间的总天数,然后利用这个总天数来确定给定日期是星期几。
2.1、源码weekday.c
#include <stdio.h>
/* 定义程序的主入口点 */
void main()
{
/* 初始化变量 */
int year, month, day, week, leap;
int sum = 0;
int i;
/* 从用户输入中获取日期 */
scanf("%d/%d/%d", &year, &month, &day);
/* 计算从1990年到输入年份之间的天数 */
for (i = 1990; i < year; i++)
{
/* 判断是否为闰年并累加天数 */
if ((i % 4 == 0 && i % 100 != 0) || i % 400 == 0)
{
sum += 366;
}
else
{
sum += 365;
}
}
/* 判断输入年份是否为闰年 */
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
{
leap = 1;
}
else
{
leap = 0;
}
/* 根据月份计算天数 */
switch (month - 1)
{
case 11:
sum += 30;
case 10:
sum += 31;
case 9:
sum += 30;
case 8:
sum += 31;
case 7:
sum += 31;
case 6:
sum += 30;
case 5:
sum += 31;
case 4:
sum += 30;
case 3:
sum += 31;
case 2:
sum += 28 + leap;
case 1:
sum += 31;
}
/* 累加天数得到总天数 */
sum += day;
/* 计算星期 */
week = sum % 7;
/* 根据计算结果输出星期 */
if (week != 0)
{
printf("%d年%d月%d日是星期%d\n", year, month, day, week);
}
else
{
printf("%d年%d月%d日是星期日\n", year, month, day);
}
}
2.2、查看圈复杂度
1、
sudo apt install python-pip
2、
sudo pip install lizard
3、
4、可以看到,代码的圈复杂度为20
三、优化后的代码
3.1、源码
#include <stdio.h>
/* 1990年1月1日 是星期一 */
int isLeapYear(int year);
int daysInMonth(int year, int month) {
static const int daysPerMonth[2][12] = {
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
return daysPerMonth[isLeapYear(year)][month - 1];
}
int isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
void printDayOfWeek(int year, int month, int day) {
int daysFromStart = 0;
int leap = isLeapYear(year);
// 计算从1990年到指定年份之前的天数
for (int i = 1990; i < year; i++) {
daysFromStart += isLeapYear(i) ? 366 : 365;
}
// 加上指定年份到指定月份之前的天数
for (int i = 1; i < month; i++) {
daysFromStart += daysInMonth(year, i);
}
// 加上指定月份的天数
daysFromStart += day;
// 计算是星期几
int week = (daysFromStart - 1) % 7 + 1; // 1990年1月1日是星期一,所以需要-1后取模
// 打印结果
printf("%d年%d月%d日是星期%d\n", year, month, day, week);
}
int main() {
int year, month, day;
scanf("%d/%d/%d", &year, &month, &day);
printDayOfWeek(year, month, day);
return 0;
}
3.2、查看圈复杂度
可以看到,圈复杂度降低了,这里是采用提取函数(Extract Method)的方式实现的。