Describe:in the project development process, often require cyclomatic complexity is not more than 10, sometimes written write the cyclomatic complexity is very large, I have seen in the project code function ring complexity greater than 100 function, because of historical reasons, the code more accumulate, no one went out to refactor, resulting in difficult to understand and maintain, So in the early stages of coding should have a requirement in mind, that is, cyclomatic complexity can not exceed 10, if more than 10, it must be the code logic is too complex to write, to go back tothink about how to break down functions and make the process easy to understand. This paper mainly introduces some examples to introduce the process of reducing cyclomatic complexity based on table method. Example 1: A simple game control functionYou may encounter code similar to the following:
if (Strcmpi (command, "north") = = 0) { if (Cur_location->north) gotolocation (Cur_location->north); else Print ("Cannot go There");} else if (strcmpi (Command, "east") = = 0) { if (cur_location->east) gotolocation (cur_location->east); else Print ("Cannot go There");} else if (strcmpi (Command, "south") = = 0) { if (Cur_location->south) gotolocation (Cur_location->south); else Print ("Cannot go There");} else if (strcmpi (Command, "west") = = 0) { if (cur_location->west) gotolocation (cur_location->west); else Print ("Cannot go There");}
from the above to see the function of the cyclomatic complexity of 13, including a lot of branches, not easy to understand and maintenance, and subsequent to add new features are also prone to error, you can use the following ways to improve.
After modification:
Enum SIDE {Side_north = 0, Side_east, Side_south, side_west};struct COMMAND { const char * name; SIDE SIDE;}; static const COMMAND commands[] = {"North ", Side_north}, {"East", Side_east}, {"South", Side_south}, {"West", side_west},};for (int i = 0; i < num_of (commands); i++) if (Strcmpi (commands[i].name, command) = = 0) { C7/>side d = commands[i].side; if (Cur_location->sides[d]) gotolocation (Cur_location->sides[d]); else Print ("Cannot go there"); }
The above rectification makes the loop complexity of the function 5, becomes very clear and easy to maintain.
Example 2: Calculate the function of renting a CD price
Double result = 0;switch (movietype) {case movie.regular: result + = 2; if (daysrented > 2) result + = (daysRented-2) * 1.5; break; Case Movie.new_release: result + = daysrented * 3; break; Case Movie.childrens: result + = 1.5; if (daysrented > 3) result + = (daysRented-3) * 1.5; break;}
Modified version:
Enum Movietype {Regular = 0, newrelease = 1, childrens = 2}; Regular newrelease childrensconst double initialcharge[] = {2, 0, 1.5};const double Initialdays[] = {2, 0, 3};const double multiplier[] = {1.5, 3, 1.5}; double Price = Initialcharge[movie_type];if (daysrented > Initialdays[movie_type]) Price + = (daysrented-initialdays[movie_ Type]) * Multiplier[movie_type];
In fact, you can also use inheritance to solve many of the switch case branches above, with one class to introduce regular price, another class new releases price, one class calculates children's movie price.
Example 3: Judging characters and numbers
Sometimes it is necessary to determine whether a character is a number or a case, and we often use the following method:
int isalnum (int ch) { return ' a ' <= ch && ch <= ' Z ' | | ' A ' <= ch && ch <= ' Z ' | | ' 0 ' <= ch && ch <= ' 9 ';}
However, in the C runtime to determine whether the numbers and letters are used in the following way, such as Ctype.h
static const unsigned char properties[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16,160,160,160,160,160,160,160,160,160,160,160,160,160,160,1 60, 204,204,204,204,204,204,204,204,204,204,160,160,160,160,160,160, 160,202,202,202,202,202,202,138,138,138,138,138,138,138,138,138, 138,138,138,138,138,138,138,138,138,138,138,160,160,160,160,160, 160,201,201,201,201,201,201,137,137,137,137,137,137,137,137,137, 137,137,137,137,137,137,137,137,137,137,137,160,160,160,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0,}; #define ISLOWER (CH) (Properties[ch] & 0x01) #define ISUPPER (CH) (Properties[ch] & 0x02) #define IsDigit (CH) (Properties[ch] & 0x04) #define ISALNUM (CH) (Properties[ch] & 0x08) #define ISSPACE (CH) (Properties[ch] & 0x10 ) #define ISPUNCT (CH) (Properties[ch] & 0x20) #define ISXDIGIT (CH) (Properties[ch] & 0x40) #define ISGRAPH (CH) (pro PERTIES[CH] & 0x80)
If you need to store less information, you can take a bit array, but you need more action to retrieve the value, as follows:
inline int isalnum (int ch) { static const unsigned int alnum[] = { 0x0, 0x3ff0000, 0x7fffffe, 0x7fffffe, 0x0, 0x0, 0x0, 0x0, }; Return (Alnum[ch >> 5]) & (1 << (Ch & 31));}
As can be seen from Example 3, the good use of arrays can effectively reduce the complexity of the program, and sometimes improve the efficiency of execution, but in the development process is still based on maintainability and understandable, unless you need to consider the performance indicators on the critical path.
Reduce the complexity of code circle based on table method