構建之法第二次作業
GIT地址 |
|
GIT用戶名 |
15881450273 |
學號后五位 |
62518 |
博客地址 |
|
作業鏈接 |
一、 背景
阿超家里的孩子上小學一年級了,這個暑假老師給家長們布置了一個作業:家長每天要給孩子出一些合理的,但要有些難度的四則運算題目,並且家長要對孩子的作業打分記錄。
作為程序員的阿超心想,既然每天都需要出題,那何不做一個可以自動生成小學四則運算題目與解決題目的命令行 “軟件”呢。他把老師的話翻譯一下,就形成了這個軟件的需求:
程序接收一個命令行參數 n,然后隨機產生 n 道加減乘除(分別使用符號+-*/來表示)練習題,每個數字在 0 和 100 之間,運算符在 2 個 到 3 個之間。
由於阿超的孩子才上一年級,並不知道分數。所以軟件所出的練習題在運算過程中不得出現非整數,比如不能出現 3÷5+2=2.6 這樣的算式。
練習題生成好后,將生成的 n 道練習題及其對應的正確答案輸出到一個文件 subject.txt 中。
當程序接收的參數為4時,以下為一個輸出文件示例。
13+17-1=29
11*15-5=160
3+10+4-16=1
15÷5+3-2=4
這次阿超選擇使用他最拿手的 C++ 語言來完成這樣的需求,工欲善其事必先利其器,第一步就需要先安裝一個好用的 IDE ,在這里我們推薦使用 Visual Studio 2017。
二、. 配置環境
首先是配置visual studio,在本機上面自己已經在之前就配置完成,這一次就直接使用。
三、克隆項目
Step1:進入阿超所放代碼的倉庫
首先是在進入存放阿超所放四則運算生成器 v1.0代碼的倉庫,在這里可以直接看到四則運算生成器的代碼目錄,這正是我接下來即將實驗的目錄代碼。
Step2:點擊Fork拷貝到自己的同名倉庫
這里我點擊右上角的 Fork ,將阿超的四則運算庫拷貝到自己的同名倉庫中,如上圖操作所示,目的就是方便后期問我自己的代碼能夠上傳到阿超所放代碼的倉庫。
Step3:檢查是否復制成功
通過進入自己的本地倉庫進行查看,觀察到本地倉庫也含有一個同名的四則運算生成器代碼倉庫。
Step4:安裝git
由於之前對git和gitup有一定的認識,大概在大二的時候就裝了git,真好暑期javaweb團隊項目也使用過它進行版本控制,從而本次實驗就直接使用了。
Step5:利用git將項目克隆島本地
首先我直接在桌面上,右鍵打開 Git 命令行軟件,輸入git clone https://github.com/15881450273/ AchaoCalculator.git,最終在我的桌面上生成了Calculator代碼倉庫文件夾。
Step6:創建項目文件夾
在完成上述五步操作后,這里與倉庫同名的文件夾Calculator ,這就是克隆到本地的項目,之后進入到剛剛克隆下來的文件夾內,並創建自己的四則運算項目文件夾,並以自己的gitup命名-15881450273,最后再進行算法代碼操作。
四、算法設計
4.1算法思想及其改進
在這里我為了能夠更直觀的顯示出設計的四則運算輸出,我做一個桌面應用程序的界面直觀展示生成的四則運算等式,把算法代碼直接寫在底層的類中,最后把屏幕上顯示的等式存入到指定文件中。
針對本次代碼有深刻感受,前面的代碼設計得太過於臃腫復雜所有的生成等式的代碼都寫在了Makequality這個類里面,總感覺不舒服,在這里我又進行了簡單的改進和優化,利用設計模式里面的簡單工廠模式把生成兩個符號和三個符號的等式進行分離分別設計了兩個不同具體產品角色:Makequality、Makefour,再設計了一個等式的生成工廠角色:Calculator,最后還設計了一個抽象產品角色:equality。自己大概簡單畫了一個不是很規范的類圖如下:
工廠方法模式重構圖
4.2部分代碼:
Equality(工廠類):
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace calculation { public partial class From1 : Form { //ArrayList shizi = new ArrayList(); String[] shizi = new String[10000]; String[] shizi1 = new String[10000]; String[] shizi2 = new String[10000]; public From1() { InitializeComponent(); } public void button1_Click(object sender, EventArgs e) { if (textBox2.Text == "") { textBox1.Text = ""; MessageBox.Show("未輸入生成計算題數量!"); } else { textBox1.Text = ""; int num; Makequality gen = new Makequality(); Makefour m = new Makefour(); num = Convert.ToInt32(textBox2.Text); int n1 = num / 2; int n2 = num / 2; shizi1 = gen.fun3(n1); shizi2 = m.fun4(n2); shizi1.CopyTo(shizi, 0); shizi2.CopyTo(shizi, shizi1.Length); if (checkBox1.CheckState == CheckState.Checked) for (int i = 0; i < num; i++) textBox1.Text = textBox1.Text + (i + 1).ToString() + ": " + shizi[i] + Environment.NewLine; else { for (int i = 0; i < num; i++) { String[] str = shizi[i].Split('='); textBox1.Text = textBox1.Text + (i + 1).ToString() + ": " + str[0] + '=' + Environment.NewLine; } } } } public void textBox2_KeyPress(object sender, KeyPressEventArgs e) { if (!(Char.IsNumber(e.KeyChar)) && e.KeyChar != (char)13 && e.KeyChar != (char)8) e.Handled = true; } public void button2_Click(object sender, EventArgs e) { if (textBox1.Text == "") MessageBox.Show("無計算題,無法導出!"); else { FileStream fs = new FileStream(".\\text.txt", FileMode.Create); StreamWriter sw = new StreamWriter(fs); sw.Write(textBox1.Text); sw.Flush(); sw.Close(); fs.Close(); MessageBox.Show("您的四則運算題目生成成功並導出,請注意查收計算題導出成功!"); } } public void checkBox1_CheckedChanged(object sender, EventArgs e) { try { textBox1.Text = ""; int num; num = Convert.ToInt32(textBox2.Text); if (checkBox1.CheckState == CheckState.Checked) for (int i = 0; i < num; i++) textBox1.Text = textBox1.Text + (i + 1).ToString() + ": " + shizi[i] + Environment.NewLine; else { for (int i = 0; i < num; i++) { String[] str = shizi[i].Split('='); textBox1.Text = textBox1.Text + (i + 1).ToString() + ": " + str[0] + '=' + Environment.NewLine; } } } catch (Exception ) { MessageBox.Show("請先輸入題目"); } } public void button3_Click(object sender, EventArgs e) { } public void From1_Load(object sender, EventArgs e) { } } }
Makequality(具體產生兩個符號等式類):
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace calculation { public class Makequality { public String[] fun3(int num) { char[] opt = new char[4] { '+', '-', '×', '÷'}; int a, b, c, opt1, opt2, res1=0, res2=0, temp; bool flag1, flag2, changed; ArrayList shizi = new ArrayList(); Random rd = new Random(); for(int i = 0; i < num; i++) { opt1 = rd.Next(1, 5); a = rd.Next(1, 100); b = rd.Next(1, 100); flag1 = false; while (true) { // 如果第一部分能夠符合標准,確定第一個式子 if (flag1) break; else { a = rd.Next(1, 100); b = rd.Next(1, 100); } switch (opt1) { case 1: if (a + b < 100) { flag1 = true; res1 = a + b; } break; case 2: if (a - b > 0) { flag1 = true; res1 = a - b; } else { temp = a; a = b; b = temp; flag1 = true; res1 = a - b; } break; case 3: if (a * b < 100) { flag1 = true; res1 = a * b; } break; case 4: if (a % b == 0) { flag1 = true; res1 = a / b; } else if (b % a == 0) { temp = a; a = b; b = temp; flag1 = true; res1 = a / b; } break; } } // 第二部分 opt2 = rd.Next(1, 5); c = rd.Next(1, 100); flag2 = false; changed = false; while (true) { if (flag2) break; else { opt2 = rd.Next(1, 4); c = rd.Next(1, 100); changed = false; } switch (opt2) { case 1: if (res1 + c < 100) { flag2 = true; res2 = res1 + c; } break; case 2: if (res1 - c > 0) { flag2 = true; res2 = res1 - c; } else { temp = res1; res1 = c; c = temp; flag2 = true; res2 = res1 - c; changed = true; } break; case 3: if (res1 * c < 100) { flag2 = true; res2 = res1 * c; } break; case 4: if (res1 % c == 0) { flag2 = true; res2 = res1 / c; } else if (c % res1 == 0) { temp = res1; res1 = c; c = temp; flag2 = true; res2 = res1 / c; changed = true; } break; } } if (changed) //如果符號改變 if (opt1 > 2 && opt2 <= 2) shizi.Add(res1.ToString() + opt[opt2 - 1] + a.ToString() + opt[opt1 - 1] + b.ToString() + "=" + res2.ToString()); else shizi.Add(res1.ToString() + opt[opt2 - 1] + "(" + a.ToString() + opt[opt1 - 1] + b.ToString() + ")=" + res2.ToString()); else if (opt1 <= 2 && opt2 > 2) shizi.Add("(" + a.ToString() + opt[opt1 - 1] + b.ToString() + ")" + opt[opt2 - 1] + c.ToString() + "=" + res2.ToString()); else shizi.Add(a.ToString() + opt[opt1 - 1] + b.ToString() + opt[opt2 - 1] + c.ToString() + "=" + res2.ToString()); } return (string[])shizi.ToArray(typeof(string)); } public string[] fun3() { throw new NotImplementedException(); } } }
4.3效果展示
Step1:輸入生成算術題數目20
Step2:點擊生成題目
Step3:點擊顯示計算結果
Step4:點擊導出題目txt
Step5:進入目錄檢查題目txt
五、單元測試
5.1添加單元測試項目:CalculatorUnitTest
5.2、配置將原來項目設置成類庫,並編譯后在CalculatorUnitTest,進行單元測試。
Step1:測試生成具體角色Makefour(生成三個符號的四則運算)
這里我用的是隨機生成三個等式進行測試。
Step2:測試生成具體角色Makequality(生成兩個符號的四則運算)
Step3:測試工廠角色生成四則運算是否正常
遇到的問題:在編譯完成添加類庫的時候始終是找不到引用的方法,最后解決的頒發就是將其所有類公用前面加一個public最后解決了關於引用不成功的問題。
六、基本操作
6.1、斷點
進行斷點調試:
6.2、單步運行
快捷鍵F10單步運行效果:
6.3、條件斷點
七、回歸測試
回歸測試是指修改了舊代碼后,重新進行測試以確認修改沒有引入新的錯誤或導致其他代碼產生錯誤。自動回歸測試將大幅降低系統測試、維護升級等階段的成本。
回歸測試作為軟件生命周期的一個組成部分,在整個軟件測試過程中占有很大的工作量比重,軟件開發的各個階段都會進行多次回歸測試。這里我修改了一下做回歸測試
八、效能工具介紹
Step1:點擊主菜單欄下分析選項中的性能探查器
Step2:選擇性能向導
選擇好性能向導之后點擊開始。
Step3:在性能向導中選擇測量函數調用計數和用時,這里可以對每一個函數單獨分析其性能情況
Step4:得到性能分析結果,可選擇想要分析的內容進行查看
Step5:針對具體項對功能進行優化
九、提交代碼
Step1:首先將自己的代碼整理完畢之后就鼠標點擊git bush here
Step2:輸入用戶名密碼上傳中:
Step3:轉到總的倉庫: