(我LJL是多餘的那個,跟張敏老師商量以後成立了這個三人小組)
張翔:201521123107
李嘉廉:201521123091
林正晟:201521123084
結對編程碼雲地址:https://gitee.com/ljl36/pair_programmingjava
(1)現有代碼的改進
①啓用了錯誤歷史記錄;
②改正一些錯誤的編碼和用法;
③修改代碼樣式;
④修改掉了若是錯題集只有一道題,複習多道題時出現如出一轍的多道題的bug;
⑤修正了界面中「開始」按鈕能夠重複點擊的問題;
⑥修改了計時框中的計時能夠隨意更改的問題;
⑦發現並修改了界面左下角正確率顯示不正確的問題。
(2)新開發功能的分析
①加入了乘方和括號參與運算
②隨機產生更加複雜的表達式
③更增強大的去重算法git
(1)代碼規範
ⅰ.使用tab進行代碼縮進
ⅱ.斷行與空白的{}行
‘{’與if和for在同一行,操做符的兩邊各留一個空格,逗號和分號也各留一個空格,以下圖:算法
ⅲ.命名規範沿用原項目命名規則:編程
Arithmetic類 astr 返回答案字符串 qstr 返回問題字符串 int_operation() 整數計算函數 fra_operation() 分數計算函數 common_divisor(int m,int n) 公約數計算函數 toString() 輸出函數 Frame類 hs 實例化History hh 實例化QA_List timer 實例化Work_Time Time 計時器動態窗口 answer1~10 輸入窗口 Review 複習按鈕 question1~10 題目顯示標籤 Right_answer1~10 正確答案顯示標籤 Tip1~10 提示正確與否標籤 Time_cost 所花時間顯示標籤 Right_percent 正確率顯示標籤 Set_question 開始按鈕 jLabel5 歷史正確題數 jLabel7 歷史總題數 rn 單次正確題數 tot 單次總題數 Frame() Frame構造函數 initComponents() 窗體顯示 xxxClicked(KeyEvent evt) 點擊事件 KeyPressed(JLabel i,JLabel j,JLabel l,int x,JTextField k) 點擊事件批量處理函數 Hide() 使不須要的輸入窗口關閉 Tip(String answer,int i)提示對錯並計入 Histroy類 qstr 問題字符串 astr 答案字符串 str 答案+問題字符串(寫入文件) str2 正確題數+總題數字符串(寫入文件) tot 總題數 rn 正確題數 qstrlist 問題字符串列(讀入文件) astrlist 答案字符串列(讀入文件) scan(String qstr,String astr) qstr+" "+astr scan2(int tot,int rn) tot+" "+rn Histroy_create() 歷史文檔生成 Histroy_save() 存儲歷史題目與答案 Histroy_saveNum() 存儲歷史題目數目 Histroy_read() 讀入歷史題目與答案 History_num() 讀入歷史題目數目 QA_List類 i 加入列題目個數 Qusetion 問題字符串列 Answer 答案字符串列 QA_List() QA_List構造函數 Test_Number類 i 顯示Test_Number窗體次數 l 語言轉化參數標識 Cancel_Button 取消按鈕 Sure_Button 肯定按鈕 English 英文界面標籤 Simplified_Chinese 簡體中文界面標籤 Traditional_Chinese 繁體中文界面標籤 Number 所需題數 Test_Number() Test_Number構造函數 initComponents() Test_Number窗體顯示 xxxClicked(KeyEvent evt) 點擊事件 Test類 main(String[] args) Work_Time類 x 00:00.x y 00:y.00 z z:00.00
ⅳ.局部變量和方法按照駝峯風格命名,類名採用Pascal風格segmentfault
(2)PSP表格dom
PSP2.1 | Personal Software Process Stages | Estimated time(min) | Actual time(min) |
---|---|---|---|
Planning | 計劃 | 60 | 60 |
· Estimate | 估計這個任務須要多少時間 | 60 | 60 |
Development | 開發 | 720 | 687 |
· Analysis | 需求分析 | 120 | 60 |
· Coding Standard | 代碼規範 | 30 | 45 |
· Design | 具體設計 | 90 | 72 |
· Coding | 具體編碼 | 300 | 240 |
· Code Review | 代碼複審 | 60 | 120 |
· Test | 測試(自我測試,修改代碼,提交修改) | 120 | 150 |
Reporting | 報告 | 150 | 168 |
測試報告 | 60 | 60 | |
計算工做量 | 30 | 48 | |
並提出過程改進計劃 | 60 | 60 |
(3)流程
ide
(4)關鍵函數類圖
函數
(5)單元測試、迴歸測試、覆蓋率
①單元測試
因爲咱們要進行單元測試的方法爲私有方法,但
[深刻JUnit] 爲何別測試private函數建議咱們不對私有方法進行單元測試。即使如此咱們仍是嘗試着作了一下:
post
②迴歸測試
迴歸測試是指修改了舊代碼後,從新進行測試以確認修改沒有引入新的錯誤或致使其餘代碼產生錯誤。咱們隊伍是隻保留了原有項目的UI界面,故不具有進行迴歸測試的條件。
③覆蓋率
覆蓋率解讀:
根據生成的數據能夠看到
ⅰ.QA_List.java的覆蓋率爲100%;
ⅱ.Test.java中有一個Test方法沒有執行影響到了覆蓋率,這也是咱們百思不得其解的一個問題;
ⅲ.Work.java的覆蓋率問題是由於咱們在測試時的記錄耗時過短而沒有記錄到;
ⅳ.Frame.java的覆蓋率不高是由於咱們在執行時沒有選擇進行語言的切換,在以後的測試中咱們進行語言切換後,覆蓋率會大幅增長;
ⅴ.Histroy.java中,由於在錯題文件已經存在的狀況下,建立文件的代碼不會被覆蓋,從而影響了覆蓋率;
ⅵ.Arithmetic.java因爲咱們保留了必要的無參構造器而下降了覆蓋率。
(6)效能分析
效能分析咱們使用老師提供的JProfiler,JProfiler的內存視圖部分能夠提供動態的內存使用情況更新視圖和顯示關於內存分配情況信息的視圖。全部的視圖都有幾個彙集層而且可以顯示現有存在的對象和做爲垃圾回收的對象。
①總體效能分析:
單元測試
②活動內存:
③線程:
④CPU:
⑤垃圾回收器:
public class Arithmetic { private static int count(char c) { if (c == '=') return 0; if (c == '(') return 1; if (c == '+') return 2; if (c == '-') return 3; if (c == '*') return 4; if (c == '/') return 5; if (c == '^') return 6; return 7; } private static boolean isNum(String exp, int pos) { char ch = exp.charAt(pos); if (ch >= '0' && ch <= '9') { return true; } return false; } private static String trans(String exp) { // 負數都用括號括起來 for (int i = 0; i < exp.length(); i++) { if (exp.charAt(i) == '-' && exp.charAt(i - 1) == '(') { exp = exp.substring(0, i) + '0' + exp.substring(i, exp.length()); i++; } } // System.out.println(exp); String postexp = new String(); int lpri[] = { 0, 1, 3, 3, 5, 5, 7, 8 }; // =(+-*/^) int rpri[] = { 0, 8, 2, 2, 4, 4, 6, 1 }; ArrayList<Character> op = new ArrayList<>(); op.add('='); for (int i = 0; i < exp.length();) { if (isNum(exp, i)) { while (i < exp.length() && isNum(exp, i)) { postexp += exp.charAt(i); i++; } postexp += '#'; } else { if (lpri[count(op.get(op.size() - 1))] < rpri[count(exp.charAt(i))]) { op.add(exp.charAt(i)); i++; } else if (lpri[count(op.get(op.size() - 1))] == rpri[count(exp.charAt(i))]) { op.remove(op.size() - 1); i++; } else { postexp += op.get(op.size() - 1); op.remove(op.size() - 1); } } } while (!op.isEmpty() && op.get(op.size() - 1) != '=') { postexp += op.get(op.size() - 1); op.remove(op.size() - 1); } return postexp; } // 操做數不超過5個,操做符不超過4個,括號不超過3對,乘方只能有一個,並且次數只能小於等於3 private static final int MAX_NUMS = 5; private static final int MIN_NUMS = 2; private static final int MAX_PAIRS = 2; private static String generateNewExp() { // 產生基本的算式 String exp = new String(); Random random = new Random(); int nums = random.nextInt(MAX_NUMS - MIN_NUMS + 1) + MIN_NUMS; int pairs = random.nextInt(MAX_PAIRS + 1); HashMap<Integer, Integer> leftPosMap = new HashMap<>(); HashMap<Integer, Integer> rightPosMap = new HashMap<>(); for (int i = 0; i < nums; i++) { leftPosMap.put(i + 1, 0); rightPosMap.put(i + 1, 0); } for (int i = 0; i < pairs; i++) { int leftPos = random.nextInt(nums) + 1; int rightPos = random.nextInt(nums - leftPos + 1) + leftPos; leftPosMap.put(leftPos, leftPosMap.get(leftPos) + 1); rightPosMap.put(rightPos, rightPosMap.get(rightPos) + 1); } boolean hasPow = false; for (int i = 0; i < nums; i++) { boolean needContinue = false; if (i != 0) { int op = random.nextInt(5); switch (op) { case 0: exp += "+"; break; case 1: exp += "-"; break; case 2: exp += "*"; break; case 3: exp += "/"; break; default: if (hasPow) { needContinue = true; i--; } else { exp += "^"; hasPow = true; } break; } if (needContinue) { continue; } } int leftNums = leftPosMap.get(i + 1); for (int j = 0; j < leftNums; j++) { exp += "("; } if (exp.length() > leftNums && exp.charAt(exp.length() - leftNums - 1) == '^') { int matchPos = i + 1; for (int j = 0; j < leftNums; j++) { exp = exp.substring(0, exp.length() - 1); while (rightPosMap.get(matchPos) <= 0) { matchPos++; } rightPosMap.put(matchPos, rightPosMap.get(matchPos) - 1); } exp += random.nextInt(4); } else { int generateNum = (random.nextInt(40) - 20); if (generateNum < 0 && (leftPosMap.get(i + 1) == 0 || rightPosMap.get(i + 1) == 0)) { exp += "(" + generateNum; rightPosMap.put(i + 1, rightPosMap.get(i + 1) + 1); } else { exp += generateNum; } } int rightNums = rightPosMap.get(i + 1); for (int j = 0; j < rightNums; j++) { exp += ")"; } } return exp; // 加括號 }
主界面:
各語言下的答題界面:
複習:
錯題集:
答題歷史:
通常般吧,就是一開始不是很能理解爲何禁用加法和乘法的結合律,後來才知道原來禁用告終合律才能使用標準答案就是最小表示法,以前在POJ上有作過樹的最小表示法,因此基本上就是平推過去了。(1+2)+3,第一個+是第二個+的子樹,啓用結合律的話,能夠將第一個+的子樹往上提,即只維護一個+號的子樹。編程也基本上沒什麼難度,只要找到加號往上找他的父節點就好了。不過沒那麼多時間再改了。 兩個隊友還挺不錯的,學東西很認真,給他們複習了一遍四則運算的後綴表達式算法和Git的使用,學得都挺快的。 就是節奏稍微有點拖,咱們團隊的執行力還不夠。 不過還好,報告寫得挺不錯的,嘿嘿嘿嘿嘿,反正之後團隊編程也要繼續磨合。 1+1+1>3,還闊以,還闊以,ACM配置,hhhh (PS:仍是想找一個妹子結對編程,最好是像實慄那樣的,謝謝。)