熟悉使用工具 ---- 《构建之法》第二次作业
GIT地址 | https://github.com/vchopin |
---|---|
GIt用户名 | vchopin |
学号后五位 | 62312 |
博客地址 | Vchopin |
作业链接 | https://www.cnblogs.com/harry240/p/11515697.html |
GIT配置
GIt注册
之前因为需要在网上抄代码,所以很早就注册了git。上面的人又有才,代码又写得好,个个都是人才,我超喜欢那里的。废话不多说,直接上图
接下里进入这个分支,可以看到我已经Fork了,并将其加入到自己的仓库中。
ssh-add id_rsa
将生成的密钥添加进来
git clone https://github.com/vchopin/AchaoCalculator.git
全部配置成功后,进行提交测试。输入
git config --global user.name "vchopin"
git config --global user.email 804862438@qq.com
完成个人仓库信息配置
1.进入到AchaoCalculator文件夹,新建一个1.txt
2.执行
git add 1.txt
加入到暂存区3.执行
git commit -m 'vchopin的提交'
提交到工作区至此,整个Git配置到此结束。
VS使用及代码分析
因为电脑上一直有VS2017,所以这里不再描述VS的配置过程
配置工作目录
新建一个控制台应用,解决方案名称为Calculator
代码编写
思路分析
我大概分析了一下最多三个操作符的情况下,估计对每个操作数写死,加上if和switch完全能够做出来,并且实现动态的生成。所以,他们都用DataTable自带的Compute()函数进行计算,或者是用逆波兰式配合栈求解,我觉得没有必要(其实我真不会逆波兰式...)。仔细分析一下,对于负数的要求,很明显,对于一年级学生,不仅结果不能是负数,同时,每一步都不能有负数。比如1-9+10=2
这个算式从左往右算的时候就会产生-8
这个数字,一年级小学生肯定没法做啊。所以只看结果是否为负数是不符合要求的。同理,也不能在运算过程中产生小数点。
编码
我打算本次代码编写分为三个步骤进行。
1.首先实现三个数的随机生成以及求和计算。第一个版本的代码比较烂,没有用函数和面向对象。只是为了把结果算出来。贴一段判断除法和减法的代码证明我很菜
2.将三个操作符这种情况添加进来。三个操作符比第一步的两个个操作符就难多了。要考虑很多种很多种情况,但是其实思路没变,也就是继续复制粘贴。但是也出现了很多问题。比如
对于最后生成的数的计算,我觉得没有生成数字难。我的想法是吧所有数字和操作符按照顺序加入到List中,然后用Contains()方法进行乘除运算,乘除之后,在按照正常的顺序加减就行了。
List<string> lstring = new List<string>();
lstring.Add(num1.ToString());
lstring.Add(op1.ToString());
lstring.Add(num2.ToString());
lstring.Add(op2.ToString());
lstring.Add(num3.ToString());
lstring.Add(op3.ToString());
lstring.Add(num4.ToString());
while (lstring.Contains("÷"))
{
int cursor = lstring.IndexOf("÷");
sum = (Convert.ToInt32(lstring[cursor - 1]) / Convert.ToInt32(lstring[cursor + 1]));
lstring.RemoveAt(cursor);
lstring.RemoveAt(cursor);
lstring[cursor - 1] = sum.ToString();
}
while (lstring.Contains("×"))
{
int cursor = lstring.IndexOf("×");
sum = Convert.ToInt32(lstring[cursor - 1]) * Convert.ToInt32(lstring[cursor + 1]);
lstring.RemoveAt(cursor);
lstring.RemoveAt(cursor);
lstring[cursor - 1] = sum.ToString();
}
if (lstring.Count == 3)
{
if (lstring[1] == "+")
sum = Convert.ToInt32(lstring[0]) + Convert.ToInt32(lstring[2]);
if (lstring[1] == "-")
sum = Convert.ToInt32(lstring[0]) - Convert.ToInt32(lstring[2]);
}
else if (lstring.Count == 5)
{
if (lstring[1] == "+")
sum = Convert.ToInt32(lstring[0]) + Convert.ToInt32(lstring[2]);
if (lstring[1] == "-")
sum = Convert.ToInt32(lstring[0]) - Convert.ToInt32(lstring[2]);
lstring[2] = sum.ToString();
if (lstring[3] == "+")
sum = Convert.ToInt32(lstring[4]) + Convert.ToInt32(lstring[2]);
if (lstring[3] == "-")
sum = Convert.ToInt32(lstring[2]) - Convert.ToInt32(lstring[4]);
}
else if (lstring.Count == 7)
{
if (lstring[1] == "+")
sum = Convert.ToInt32(lstring[0]) + Convert.ToInt32(lstring[2]);
if (lstring[1] == "-")
sum = Convert.ToInt32(lstring[0]) - Convert.ToInt32(lstring[2]);
lstring[2] = sum.ToString();
if (lstring[3] == "+")
sum = Convert.ToInt32(lstring[4]) + Convert.ToInt32(lstring[2]);
if (lstring[3] == "-")
sum = Convert.ToInt32(lstring[2]) - Convert.ToInt32(lstring[4]);
lstring[4] = sum.ToString();
if (lstring[5] == "+")
sum = Convert.ToInt32(lstring[4]) + Convert.ToInt32(lstring[6]);
if (lstring[5] == "-")
sum = Convert.ToInt32(lstring[4]) - Convert.ToInt32(lstring[6]);
}
我觉得写出这种烂代码,我也是一个程序员传奇了。代码写到这里。基本功能都能实现了,我其实也不想写了,太费神了。先上个运行图吧,有图有真相
sw.WriteLine(str);
sw.Flush();
sw.Close();
}
我是想所有算式都调用一下,那得多浪费时间,我就直接写在了一个字符串里面存着。结果写进去居然是这样...
为了防止助教小仙女打错分数,还是把写的规范的算式贴出来
<center>
<img style="border-radius: 0.3125em;
box-shadow: 0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.08);"
src="https://www.z4a.net/images/2019/09/20/image4b3ab7e368e85cac.md.png"><br>
<div style="color:orange; border-bottom: 1px solid #d9d9d9;
display: inline-block;
color: #999;
padding: 2px;">文件图</div>
</center>
  3.代码太烂了,没人看,万一给助教看不开心了,给我来个60分,多尴尬。所以,我觉得对代码进行重构是很有必要的,该集成为方法的时候就集成,该继承就继承。反正,要让代码优雅有人看。首先,把一列计算式看成对象构造line对象
```csharp
class line
{
protected int num1=0, num2=0, num3=0, num4=0;
protected char op1 ='#', op2='#', op3='#';
protected int sum = 0;
public int Num1 { get => num1; set => num1 = value; }
public int Num2 { get => num2; set => num2 = value; }
public int Num3 { get => num3; set => num3 = value; }
public int Num4 { get => num4; set => num4 = value; }
public char Op1 { get => op1; set => op1 = value; }
public char Op2 { get => op2; set => op2 = value; }
public char Op3 { get => op3; set => op3 = value; }
protected List<string> lstring = new List<string>();
/*
* Comments : 计算list的乘除法
* Param bool multi : 是否做乘法
* Author : vchopin
* @Return void
*/
protected void calMulSum(bool multi)
{
string str = "÷";
if (multi)
str = "×";
while (lstring.Contains(str))
{
int cursor = lstring.IndexOf(str);
if (multi)
sum = Convert.ToInt32(lstring[cursor - 1]) * Convert.ToInt32(lstring[cursor + 1]);
else
sum = Convert.ToInt32(lstring[cursor - 1]) / Convert.ToInt32(lstring[cursor + 1]);
lstring.RemoveAt(cursor);
lstring.RemoveAt(cursor);
lstring[cursor - 1] = sum.ToString();
}
}
/*
* Comments : 计算list的加减法
* Author : vchopin
* @Return void
*/
protected void calAddSum()
{
int i = lstring.Count;
for (int j = 1; j <= i - 2; j += 2)
{
if (lstring[j] == "+")
sum = Convert.ToInt32(lstring[j - 1]) + Convert.ToInt32(lstring[j + 1]);
if (lstring[j] == "-")
sum = Convert.ToInt32(lstring[j - 1]) - Convert.ToInt32(lstring[j + 1]);
if ((j == 1 && i >= 3) || (j == 3 && i >= 5))
{
lstring[j + 1] = sum.ToString();
}
}
}
}
然后构造两个它的子类line3和line4,分别代表3个操作数和4个操作数并重写toString()
方法
class line3:line
{
public override string ToString()
{
lstring.Add(num1.ToString());
lstring.Add(op1.ToString());
lstring.Add(num2.ToString());
lstring.Add(op2.ToString());
lstring.Add(num3.ToString());
calMulSum(false);//计算除法
calMulSum(true);//计算乘法
calAddSum();//计算加减
return num1 + "" + op1 + "" + num2 + "" + op2 + "" + num3 + "=" + sum;
}
}
class line4:line
{
public override string ToString()
{
lstring.Add(num1.ToString());
lstring.Add(op1.ToString());
lstring.Add(num2.ToString());
lstring.Add(op2.ToString());
lstring.Add(num3.ToString());
lstring.Add(op3.ToString());
lstring.Add(num4.ToString());
calMulSum(false);
calMulSum(true);
calAddSum();
return num1 + "" + op1 + "" + num2 + "" + op2 + "" + num3 + "" + op3 + "" + num4 + "=" + sum;
}
}
除此之外,将随机数封装成为一个静态类,包括生成1,100的随机数,生成随机符号,生成随机3位,4位的计算式等。最后将全部生成算式的操作放在calculate类中。
总结
总的来说,这次题目还是有点难度(不借助百度和课本),但是我觉得我这种水平一天就能完成编码工作,估计其他人几十分钟的事。但是我认为我的代码还是有很多地方需要改进。比如在选择整除数的时候,如果随机生成的除数次数太多,能不能考虑直接从合数中选择一个数和它的因数,这是一个很明显的效率改进。我在调试过程中,在整除的while循环里面耗时最多。还有,考虑到拓展问题,我这个程序肯定未来是没有办法在维护了,那到底怎么样重新构造才能更好地实现类与类之间的解耦?如果不是四个操作数,而是十个,二十个,那又该怎么升级?很多问题都没有抽象到一个相当的高度,关注的都是细枝末节的东西,我觉得这样不好。
单元测试
VSTS配置
首先在同一个解决方案下面新建一个CalculatorTest的项目
然后添加对Calculator项目的引用,并在UnitTest.cs里面进行using引用。
最后在代码中进行引用,完成配置。
calculate cal = new calculate(22);
cal.generateNum();
}
}
###开始测试
点击测试->测试资源管理器得到
<center>
<img style="border-radius: 0.3125em;
box-shadow: 0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.08);"
src="https://www.z4a.net/images/2019/09/20/01db315a3026f4dc0962f189f01cd891.png"><br>
<div style="color:orange; border-bottom: 1px solid #d9d9d9;
display: inline-block;
color: #999;
padding: 2px;">测试资源管理器</div>
</center>
我这个是已经测试过的图,点击全部运行,查看output,得到,产生22个随机数组成的没有小数没有负数的代码,与预期符合。完成代码测试。
<center>
<img style="border-radius: 0.3125em;
box-shadow: 0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.08);"
src="https://www.z4a.net/images/2019/09/20/4ba72403f523cd1674169fdf549664c2.md.png"><br>
<div style="color:orange; border-bottom: 1px solid #d9d9d9;
display: inline-block;
color: #999;
padding: 2px;">output</div>
</center>
##基本操作
>我在写程序的时候其实就已经在用断点和单步调试了,我想跳过,又怕没分...
###断点
  旨在暂停程序,查看变量。我觉得最好用的是当断点了之后,vs里面用鼠标悬浮在某个变量上面会显示当前变量的值。例如
<center>
<img style="border-radius: 0.3125em;
box-shadow: 0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.08);"
src="https://www.z4a.net/images/2019/09/20/image.md.png"><br>
<div style="color:orange; border-bottom: 1px solid #d9d9d9;
display: inline-block;
color: #999;
padding: 2px;">鼠标悬停查看变量值</div>
</center>
windows自带截屏截不出来鼠标,我这里鼠标其实是放在
`linet`上面的。这里就显示着一个等式,也就是linet的`ToString()`,对于我。还可以验证条件是否成立。本次断点下在while语句,会显示`True`或者是`False`。
  同时还可以查看局部变量、添加监视和调用堆栈。在发生错误的时候或者是要对程序进行详细优化的时候,调用堆栈就非常有用。
<center>
<img style="border-radius: 0.3125em;
box-shadow: 0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.08);"
src="https://www.z4a.net/images/2019/09/20/2181fade6041b5e14c6bc4a036b7df55.md.png"><br>
<div style="color:orange; border-bottom: 1px solid #d9d9d9;
display: inline-block;
color: #999;
padding: 2px;">查看变量和调用堆栈</div>
</center>
  在vs中,断点之后,继续执行代码的功能在顶栏
<center>
<img style="border-radius: 0.3125em;
box-shadow: 0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.08);"
src="https://www.z4a.net/images/2019/09/20/56382ad52c4401f49a4fd1115d1f99cd.png"><br>
<div style="color:orange; border-bottom: 1px solid #d9d9d9;
display: inline-block;
color: #999;
padding: 2px;">查看变量和调用堆栈</div>
</center>
  step into是进入到每一步进行执行,可能会进入到很深的层次。step over就是一句代码一句代码的执行,从你写的一行调到下一行。step out就是跳出整个过程,如果是在外层有循环会继续循环,没有就执行结束。
###条件断点
  条件断点是在触发到一定条件下才会中断程序执行。把鼠标移动到断点那个圆圈那里,就会出现一个设置符号和禁用断点符号。设置就是条件断点。
<center>
<img style="border-radius: 0.3125em;
box-shadow: 0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.08);"
src="https://www.z4a.net/images/2019/09/20/image8c451f098842cdc8.md.png"><br>
<div style="color:orange; border-bottom: 1px solid #d9d9d9;
display: inline-block;
color: #999;
padding: 2px;">条件断点</div>
</center>
###调试总结
  断点调试是一个非常有用的工具,vs里面自带的强大的变量查看功能和调用堆栈查看才是我最得心应手的功能。但是对于什么时候用条件断点还不是很清楚,所以还是应该多编代码。
##回归测试
  老师讲的回归测试就是测试过之后某一天想起再来继续测试。虽然不科学严谨,但是清晰易懂。为了验证回归测试,修改写入文件代码
```csharp
private static void writeToFile(string str)
{
StreamWriter sw = new StreamWriter("subject.txt", true);
sw.WriteLine(str);
sw.Flush();
sw.Close();
}
回归测试代码
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
System.Console.WriteLine("开始测试");
Program.writeToFile("hello 回归测试");
}
}
完成回归测试如图
Main()
消耗了31%的CPU.双击查看Main()
方法,里面标红的方法是calculator.generateNum()
,和预期结果一致。
提交代码
Git准备
开开心心打开了git bash,输入git status
,为啥没有出现那个nonthing to commmit
。
git commit -m "comment"
就可以进行提交了
Create pull requets
发起请求。完成本次试验全部内容。
试验总结
这次试验内容是真的丰富(duo)。在此锻炼了自己敲代码的生疏的手。GitHub是个好东西,居然能够看到提交次数和提交时间。我打算写完之后,在提交一个有注释的代码。但是,我在VS2017上面写代码的时候,我看到VS好像可以直接推送到GitHub上面,还支持GitHub的登录。
从实验内容上面来说,除了学会GitHub的使用和提交,还有效能分析、回归测试这三个,其他都是在吃老本。但是我觉得很有意思的是GitHub的Bash和Linux的Bash居然是一样的操作,cd
、ls -la
这些命令居然是一模一样。但是还是得多联系,搞清楚GitHub到底怎么样使用,这次试验只是抛砖引玉,更多的还得自己去发现。我相信后面的试验只会越来越难,以后还是得多敲代码,把水平提上去,不然每周一个通宵,谁顶得住啊。最后,还是冲鸭!!!