附加作業 軟體工程原則的應用例項分析
作業要求參照:[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.git
四則運算:https://git.coding.net/shishishaonian/four_arithmetic_operation.git
在詞頻統計程式碼中,我並沒有考慮到程式碼的重複利用,對每一個題目要求都編寫一個統計函式,最後整個程式碼很長,main函式寫了接近300行,閱讀起來很困難。部分程式碼如下:
int main(int argc, char** argv) { ifView Code(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; } }View Code
這樣通過呼叫外部函式的形式,使整個程式碼簡化了不少,閱讀起來也舒服方便了很多。
軟體工程中的原則僅僅應用在一兩次的作業中可能感覺不到明顯優勢,但如果應用在長期的程式碼實踐中就會使人直觀地感受到它帶來的方便與實用。不僅僅可以統一程式碼風格,還可以提高程式碼編寫速度、方便程式碼修改、提高閱讀體驗等。在以後的軟體開發中,我們應該善於使用軟體工程原則,更加合理簡便地進行軟體開發。