附加作业 软件工程原则的应用实例分析
作业要求参照:[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2446]
随着完成作业的增多,软件工程的原则也逐渐体现在作业代码里了,一些以前的坏习惯也在逐步纠正。让我印象比较深刻的是代码的重复利用这一块。这儿举两个作业进行对比,一个是词频统计,另一个是四则运算。
git地址如下:词频统计:https://git.coding.net/shishishaonian/word_count.githttps://git.coding.net/shishishaonian/word_count.githttps://git.coding.net/shishishaonian/word_count.githttps://git.coding.net/shishishaonian/word_count.git
四则运算:https://git.coding.net/shishishaonian/four_arithmetic_operation.git
在词频统计代码中,我并没有考虑到代码的重复利用,对每一个题目要求都编写一个统计函数,最后整个代码很长,main函数写了接近300行,阅读起来很困难。部分代码如下:
int main(int argc, char** argv) { if (argc == 3) { FILE *fp = NULL; fp = fopen(argv[2], "r"); char ch = fgetc(fp); int len = 0; long totalword = 0; string str = ""; map<string, int>mp; vector<string>s; vector<pair<string, int> >pa; while (ch != EOF) { ...//统计单词函数 } ...//统计词频函数 return 0; } if (argc == 2) { if (strcmp(argv[1], "-s") == 0) { char ch; int len = 0; long totalword = 0; string str = ""; map<string, int>mp; vector<string>s; vector<pair<string, int> >pa; while ((ch = getchar()) != EOF) { ...//统计单词函数 } ...//统计词频函数 return 0; } else { char buf[80]; char *myFileBasePath =getcwd(buf, sizeof(buf)); strcat(buf, "\\"); strcat(buf, argv[1]); int judgeDirResultCode = is_dir_exist(myFileBasePath); if (judgeDirResultCode == 0) { _finddata_t sfind; strcat(buf, "\\*.txt"); long lresult = _findfirst(buf, &sfind); do { string path = sfind.name; path += '\0'; FILE *fp = NULL; fp = fopen(path.c_str(), "r"); for (int i = 0; i<path.length() - 5; i++) { printf("%c", path[i]); } printf("\n"); char ch = fgetc(fp); int len = 0; long totalword = 0; string str = ""; map<string, int>mp; vector<string>s; vector<pair<string, int> >pa; while (ch != EOF) { ...//统计单词函数 } ...//统计词频函数 }while (_findnext(lresult, &sfind) == 0); return 0; } strcat(argv[1], ".txt"); FILE *fp = NULL; fp = fopen(argv[1], "r"); if (fp == NULL) { printf("该文件/文件夹不存在!\n"); return 0; } else { char ch = fgetc(fp); int len = 0; long totalword = 0; string str = ""; map<string, int>mp; vector<string>s; vector<pair<string, int> >pa; while (ch != EOF) { ...//统计单词函数 } ...//统计词频函数 return 0; } } } if (argc == 1) { char ch; int len = 0; long totalword = 0; string str = ""; map<string, int>mp; vector<string>s; vector<pair<string, int> >pa; while ((ch = getchar()) != '\n') { ...//统计单词函数 } ...//统计词频函数 return 0; } }
这部分代码中,单词统计和词频统计部分的代码是一模一样的,我是把这两个函数在主函数中写了五遍,搞得整个代码又臭又长。如果将两个功能函数在主函数外写成单独的函数,主函数中进行调用,就可以简化很多行代码,使整个代码更加利于阅读。
在四则运算中,我吸取了之前的教训,把功能函数写在了主函数之外,在需要的时候就直接进行调用。部分代码如下:
void CreateEquation(vector<char>&ve) { ... } void RPNotation(vector<char>&st,vector<char>ve) { ... } void Correct_Ans(vector<char>st,double &correctAns) { ... } void PrintfEquation(vector<char>ve) { ... } bool Is_Equal(double a,double b) { ... } int main(int argc,char** argv) { srand(time(NULL)); if(argc==1) { int rightnum=0; for(int i=0;i<20;i++) { CreateEquation(vec); RPNotation(st,vec); Correct_Ans(st,correctAns); PrintfEquation(vec); printf("\n?"); double t; scanf("%lf",&t); if(Is_Equal(correctAns,t)) { rightnum++; printf("答对啦,你真是个天才!\n"); } else { printf("再想想吧,答案似乎是%g喔!\n",correctAns); } } printf("你一共答对%d道题,共20道题。",rightnum); return 0; } if(argc==3) { string str=argv[2]; for(int i=0;i<str.length();i++) { if(str[i]>='0'&&str[i]<='9') { continue; } printf("题目数量必须是 正整数。"); return 0; } int a=atoi(str.c_str()); if(a<=0) { printf("题目数量必须是 正整数。"); return 0; } int rightnum=0,totalnum=atoi(argv[2]); FILE *fp=fopen("题目.txt","w"); for(int i=0;i<totalnum;i++) { CreateEquation(vec); RPNotation(st,vec); Correct_Ans(st,correctAns); int j; for(j=0;j<vec.size();j++) { printf("%c",vec[j]); fprintf(fp,"%c",vec[j]); } for(;j<50;j++) { printf(" "); fprintf(fp,"%c",32); } Fraction f1=(correctAns); f1.Print(); //printf("%g\n",correctAns); //fprintf(fp,"%g\n",correctAns); } return 0; } }
这样通过调用外部函数的形式,使整个代码简化了不少,阅读起来也舒服方便了很多。
软件工程中的原则仅仅应用在一两次的作业中可能感觉不到明显优势,但如果应用在长期的代码实践中就会使人直观地感受到它带来的方便与实用。不仅仅可以统一代码风格,还可以提高代码编写速度、方便代码修改、提高阅读体验等。在以后的软件开发中,我们应该善于使用软件工程原则,更加合理简便地进行软件开发。