本次開發的軟件是爲幫助小學老師解決出題麻煩且不高效的問題,通過和夥伴尉安瑞的共同合做,製做出了一個可以自動生成四則運算且能計算出結果的軟件。html
在一開始設計的時候,夥伴明確的指出採用MVC模式進行軟件設計,趕忙百度一下什麼是MVC,原來這是一種軟件設計典範,把軟件分紅三部分模型(Model)、視圖(View)和控制器(Controller)進行開發,這樣會更高效,視圖層和業務層分離,代碼耦合性低,複用性高,不至於出現改一處而改所有,讓軟件沒法開發下去。
c++
這些都是原子操做,只受C層控制,其中值得一提的是在設計隨機操做符生成時,夥伴想到使用8,4,2,1來表示+,-,*,/操做符的代號之和,以後只要知道代號和,就能獲得總共有幾個操做符參與運算,它們都是什麼,而且在進行存儲的時候就能夠和操做數一塊兒進行存儲,大大下降了存儲的複雜度。git
C層依賴於M層,只要進行對M層的調用,再進行存儲便可github
因爲是結對編程,M,C層的駕駛員主要由我負責,V層則由夥伴負責,這層主要設計請參考這裏算法
/** *Summary: 隨機數生成 *Parameters: * range: 隨機數範圍 **/ int random(int range) { //srand(time(0)); return rand()%range; }
/** *Summary:隨機操做符生成 *Parameters: * opreation: 表示操做符代號之和 * + :加法,用數字8表示 * - :減法,用數字4表示 * * :乘法,用數字2表示 * / :除法,用數字1表示 *return: 操做符代號 **/ int getOperation(int opreation) { int count = 0; int i = 0; int temp = opreation; for(;i<4;i++) { count+=(temp&1); temp = temp>>1; } count = random(count); for(i = 1;i<=8;i=i*2) { if((opreation&i) != 0) { if(count==0) { return i; } else { count--; } } } }
/** *Summary:隨機操做數數生成 *Parameters: * max: 操做數取值上限 * decimal: true 表示小數 false 表示整數 * negative: true 表示負數 false 表示正數 *return: 隨機操做數 **/ float getOperand(int max, bool decimal, bool negative) { if(!decimal && !negative) { return random(max); } else if(!decimal && negative) { return -1*random(max); } else if(decimal && !negative) { return random(max)/100.0+random(99); } else { return -1*(random(max)/100.0+random(99)); } }
/** *Summary:隨機括號生成 *Parameters: * max: 表示左括號 max+1表示右括號 * left_bracket: 未匹配的左括號個數 *return: 括號代號 **/ int getBracket(int max, int &left_bracket) { if(left_bracket == 0) { return max; } else { return max+random(2); } }
/** *Summary: 進行運算 *Parameters: * myExpression: 算術表達式 **/ float evaluateExpression(char* myExpression) { // 算術表達式求值的算符優先算法 // 設OPTR和OPND分別爲運算符棧和運算數棧,OP爲運算符集合 SC *OPTR=NULL; // 運算符棧,字符元素 SF *OPND=NULL; // 運算數棧,實數元素 char tempData[20]; // 用來存儲、轉換操做數 float data, a, b; char theta, *c, Dr[] = {'#', '\0'}; // Dr[]的'#'用來使傳進來的字符串尾爲'#','\0'是字符串結束的標誌,控制其長度 OPTR = push(OPTR, '#'); c = strcat(myExpression, Dr); strcpy(tempData, "\0"); //字符串拷貝函數,讓tempData[0]爲"\0" while (*c != '#' || OPTR->c != '#') { if (!in(*c, OPSET)) { Dr[0] = *c; strcat(tempData, Dr); //字符串鏈接函數 c++; if(in(*c, OPSET)) { data = atof(tempData); //字符串轉換函數(double) OPND = push(OPND, data); strcpy(tempData,"\0"); } } else if(in(*c, OPSET)) // 不是操做數則進棧 { switch(precede(OPTR->c, *c)) { case '<': // 棧頂元素優先級低 OPTR = push(OPTR, *c); c++; break; case '=': // 脫括號並接收下一字符 OPTR = pop(OPTR); c++; break; case '>': // 退棧並將運算結果入棧 if(OPTR->c == '#') { cout << "輸入錯誤!"; break; } theta= OPTR->c; OPTR = pop(OPTR); if(OPND==NULL) { flag = false; return 0; } b = OPND->f; OPND = pop(OPND); if(OPND==NULL) { flag = false; return 0; } a = OPND->f; OPND = pop(OPND); float p = operate(a, theta, b); //p用來記錄運算後的結果 if(!flag) return 0; //若運算不合法跳出函數 OPND = push(OPND, p); break; } //switch } } //while return OPND->f; } //evaluateExpression
/** *Summary: 查重 *Parameters: * rep: 生成的表達式倉庫 * flag: 新生成的表達式下標 *return: false表示沒有重複的表示式 true反之 **/ bool recheck(Repertory* rep,int flag) { for(int i = 0; i<flag; i++)//遍歷flag行以前的表達式 { bool target = true; for(int j = 0; j<(rep->col-1); j++) { if((rep->array[i][j]!=rep->array[flag][j])) { target = false; } } if(target) { return true; } } return false; }
/** *Summary: 輸出到控制檯 *Parameters: * rep: 生成的表達式倉庫 * output: 0表示輸出到控制檯,1表示輸出到文件,2表示輸出到打印機 * isResult: true表示計算出結果,false表示不計算出結果 * isBracket:ture表示有括號,false表示沒有括號 **/ void getResult(Repertory* rep, bool isResult, bool isBracket) { int n = 0; //記錄左括號數 bool turn = false; //標誌,當操做符後有括號時爲true,避免出現一個操做數被一對括號套住 for(int i = 0;i<(rep->row);i++) { char equation[100]={'0'}; string str=""; for(int j = 0;j<(rep->col-1);j++) { if(j%2==0) { if(j==0&&isBracket&&random(2))//第一位操做數是否生成左括號 { str+="("; cout << "("; n++; } str+= to_string(rep->array[i][j]); //將操做數放到字符串str中 if(j!=0&&isBracket&&random(2)&&n!=0&&!turn)//是否須要生成右括號 { n--; str+=")"; cout<<rep->array[i][j]<<")"; } else { turn = false; cout<<rep->array[i][j]; //打印單個操做數 } } else { str+=configure[(int)rep->array[i][j]-1];//將操做符放到字符串str中 if(isBracket&&random(2)&&((rep->col-j)/2>n+1)) //是否須要生成左括號 { turn = true; n++; str+="("; cout<<configure[(int)(rep->array[i][j])-1]<<"("; } else { cout<<configure[(int)(rep->array[i][j])-1];//打印單個操做符 } } } while(n!=0) { str+=")"; cout << ")"; n--; } cout << "="; strcpy(equation, str.c_str()); //將字符串str轉換爲字符數組equation if(isResult) { calculate(equation); //計算並打印出結果 } cout <<endl; } }
小夥伴是一位特別有經驗的人,在拿到題目時,他首先提出了此次軟件的開發模式,並很快的進行模塊化的分解,這也是本次開發可以快速高效進行的一大重要因素;在開發過程當中,他思惟敏捷、清晰,老是能在關鍵的地方提出很是有建設性的建議,就像當咱們在肯定如何生成隨機運算符時,他給出了一個很高效的算法,把+,-,*,/用數字8,4,2,1表示,並用他們之間的代數和來表示總共有幾種操做符及都是哪些,這樣一來即解決了問題,也避免了去使用多重條件語句來判斷,提升了編程的效率;同時他也是一位穩重的人,在咱們進行討論的時候,我老是一有想法就立馬講出來,並無通過本身的仔細推敲,每每會形成打亂咱們的編程節奏,使之偏離方向,而夥伴則會通過仔細的推敲驗證後纔會把本身的想法提出來,而且可靠性很強;他仍是一位有耐心,有團隊精神的人,在出現我沒搞明白的地方時,他會耐心的和我講解,讓我很快的跟上節奏;他很注重細節,在給變量、函數等命名時,必定要找到一個能很容易看明白的詞,而且一開始就和我統一編碼風格和註釋風格,應爲這是結對編程,不是一我的進行開發,讓對方很快的明白代碼的意思很重要。編程
總之,他的這些優勢都是值得我去學習的,很開心能和他一塊兒合做開發。數組
本次結對編程, 對我感觸最大的就是建一個適合該工程的好模型。可能對於一個小項目,拿來直接就上手,通常來講都沒太大問題,但只要稍微的加大點難度,再增長點功能,沒有一個好的模型支撐,寫到後面確定是要亂的,即便你寫下來了,可擴展性和可維護性是極差的。在此次編程中,我主要負責C,M層的底層開發,剛開始,都把每個功能儘量的模塊化,一切開發的都挺順利,但到了添加隨機括號時,由於當時就只差這個功能了,就只想着怎麼快速的實現,結果最後,雖然實現了,但致使代碼的複用性極低,甚至只要稍微該一點,就得對代碼進行重構,這一點很是不利於對項目的管理和維護。一樣,結對編程最大的特色就是須要兩人溝通,本身寫代碼可能不是問題,可怎麼把本身的idea有效的傳遞給對方,這就須要本身多加練習。dom
總的來講,此次結對編程讓我學習到了不少,不只在編程、設計方面,友誼方面也獲得了收獲,期待着下一次和他的合做。ide