构建之法第二次作业
GIT地址 |
https://github.com/15881450273 |
GIT用户名 |
15881450273 |
学号后五位 |
62518 |
博客地址 |
https://www.cnblogs.com/Slow-Walker/ |
作业链接 |
https://www.cnblogs.com/harry240/p/11515697.html |
一、 背景
阿超家里的孩子上小学一年级了,这个暑假老师给家长们布置了一个作业:家长每天要给孩子出一些合理的,但要有些难度的四则运算题目,并且家长要对孩子的作业打分记录。
作为程序员的阿超心想,既然每天都需要出题,那何不做一个可以自动生成小学四则运算题目与解决题目的命令行 “软件”呢。他把老师的话翻译一下,就形成了这个软件的需求:
程序接收一个命令行参数 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:转到总的仓库: