GIT地址 | https://github.com/vchopin |
---|---|
GIt用户名 | vchopin |
学号后五位 | 62312 |
博客地址 | Vchopin |
作业链接 | https://www.cnblogs.com/harry240/p/11515697.html |
GIT配置
GIt注册
之前因为需要在网上抄代码,所以很早就注册了git。上面的人又有才,代码又写得好,个个都是人才,我超喜欢那里的。废话不多说,直接上图

登陆上来就是个人账号主页

我是在写博客之前就跟着作业教程走了一部分,所以我的Repositories中已经有AchaoCalculator这个分支了。
接下里进入这个分支,可以看到我已经Fork了,并将其加入到自己的仓库中。

GitHub注册工作完成,开始配置Windows本地的的Git Bash。
Git Bash配置
首先根据教程,打开 http://git-scm.com/download/win下载Git for Windows项目
下载完成之后开始安装,首先是GNU协议,遵循GNU协议的软件好像都会有这个让你先同意的协议

刚开始用这个Windows上面的Git,啥都不懂,就一路next,但是在设置默认编辑器的时候我还是看懂了,电脑上有个VS Studio,就把它设置成了默认编辑器

开开心心就装好了Git for windows。但是在此留下一个疑问,以后来回答。如何实现软件嵌入右键菜单以及将文件拖动到图标就可以快捷打开的功能?
Clone 项目到本地
在D盘的Git/repos右键打开Git Bash输入git clone https://github.com/vchopin/AchaoCalculator.git
果然没有想象中如意,顺利出现问题。显示Permission denied.根据我纵横多年的经验,这是权限不足导致的。百度搜索了一下,还真的是。然后按照这个博文进行了设置。https://www.cnblogs.com/jayworld/p/10419985.html
1.生成ssh key在Git Bash中输入ssh-keygen -t rsa -b 2048 -C "804862438@qq.com"
我没有设置密码,一路enter,生成一对密钥
2.执行eval 'ssh-agent -s'
启用ssh代理

3.执行
ssh-add id_rsa
将生成的密钥添加进来

4.在个人GitHub上面将id_rsa.pub的内容添加进入到ssh的keys中

5.最后完成设置,开始下载。执行
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.首先实现三个数的随机生成以及求和计算。第一个版本的代码比较烂,没有用函数和面向对象。只是为了把结果算出来。贴一段判断除法和减法的代码证明我很菜


这两种代码都是我刚开始拿到题的时候的想法就是拆分成三个数字,两个符号,挨个对其进行判断就行了。代码重复率巨大。基本都是CTRL+C,CTRL+V。运行空间7M多,CPU内存20%。虽然那个啥代码看不下去,但是我这种水平,能跑起来没有错误就谢谢图灵祖师爷了。
2.将三个操作符这种情况添加进来。三个操作符比第一步的两个个操作符就难多了。要考虑很多种很多种情况,但是其实思路没变,也就是继续复制粘贴。但是也出现了很多问题。比如

在判断第一个操作符的时候,问题很多,比如后面三个数不能比前面的数大,如果后面的两个操作符是除号怎么计算,后面的数怎么按照比率减小随机范围,等等很多问题。导致了第二个demo代码十分凌乱,看了第一遍想自己重写,看了第二遍想砸电脑,看了第三遍想遁入佛门。但是我觉得我还是有写得好的地方,比如

在这个步骤里面,如果不满足就重新生成原来的随机范围也就是[1,101],效率非常低,命中率也非常低。但是改进一下算法,如果第一个数比较比后面都小,那么就让后面的数生成的随机最大范围按照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]);
}
我觉得写出这种烂代码,我也是一个程序员传奇了。代码写到这里。基本功能都能实现了,我其实也不想写了,太费神了。先上个运行图吧,有图有真相

但是这个图是好看,写到文件里面,就难看了,例如

emmmm...我是用的这个写入
private static void writeToFile(string str)
{
StreamWriter sw = new StreamWriter("subject.txt", true);
sw.WriteLine(str);
sw.Flush();
sw.Close();
}
我是想所有算式都调用一下,那得多浪费时间,我就直接写在了一个字符串里面存着。结果写进去居然是这样...
为了防止助教小仙女打错分数,还是把写的规范的算式贴出来

3.代码太烂了,没人看,万一给助教看不开心了,给我来个60分,多尴尬。所以,我觉得对代码进行重构是很有必要的,该集成为方法的时候就集成,该继承就继承。反正,要让代码优雅有人看。首先,把一列计算式看成对象构造line对象
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类,由于这个class默认是private,所以报红显示有一定的访问级别。所以在class calculate前面加上public。
[TestClass]
public class UnitTest1
{
/*
*测试calculate类
*/
[TestMethod]
public void TestMethod1()
{
System.Console.WriteLine("开始测试");
calculate cal = new calculate(22);
cal.generateNum();
}
}
开始测试
点击测试->测试资源管理器得到

我这个是已经测试过的图,点击全部运行,查看output,得到,产生22个随机数组成的没有小数没有负数的代码,与预期符合。完成代码测试。

基本操作
我在写程序的时候其实就已经在用断点和单步调试了,我想跳过,又怕没分...
断点
旨在暂停程序,查看变量。我觉得最好用的是当断点了之后,vs里面用鼠标悬浮在某个变量上面会显示当前变量的值。例如

windows自带截屏截不出来鼠标,我这里鼠标其实是放在
linet
上面的。这里就显示着一个等式,也就是linet的ToString()
,对于我。还可以验证条件是否成立。本次断点下在while语句,会显示True
或者是False
。
同时还可以查看局部变量、添加监视和调用堆栈。在发生错误的时候或者是要对程序进行详细优化的时候,调用堆栈就非常有用。

在vs中,断点之后,继续执行代码的功能在顶栏

step into是进入到每一步进行执行,可能会进入到很深的层次。step over就是一句代码一句代码的执行,从你写的一行调到下一行。step out就是跳出整个过程,如果是在外层有循环会继续循环,没有就执行结束。
条件断点
条件断点是在触发到一定条件下才会中断程序执行。把鼠标移动到断点那个圆圈那里,就会出现一个设置符号和禁用断点符号。设置就是条件断点。

调试总结
断点调试是一个非常有用的工具,vs里面自带的强大的变量查看功能和调用堆栈查看才是我最得心应手的功能。但是对于什么时候用条件断点还不是很清楚,所以还是应该多编代码。
回归测试
老师讲的回归测试就是测试过之后某一天想起再来继续测试。虽然不科学严谨,但是清晰易懂。为了验证回归测试,修改写入文件代码
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 回归测试");
}
}
完成回归测试如图


效能工具
性能探查器
用来探查程序性能的vs工具

勾选CPU效率之后,点击开始,程序开始性能探查

十秒后,完成性能探查收集

根据图片可以看到
Main()
消耗了31%的CPU.双击查看Main()
方法,里面标红的方法是calculator.generateNum()
,和预期结果一致。

因此,日后需要继续优化生成随机数字的方法。里面的时间复杂度可能是O(n^2)。
提交代码
Git准备
开开心心打开了git bash,输入git status
,为啥没有出现那个nonthing to commmit
。

赶紧查百度,直接
git commit -m "comment"
就可以进行提交了

开始提交
代码提交后,准备开始push到远程仓库AchaoCalculator输入git push
之后弹出登录框进行登录

输入自己的github用户名和密码之后,弹出SSH的确认框,这应该是我之前添加的SSH keys的连锁反应。第一次密码输错了,GitHub贴心的给我发了邮件...

用户名和密码正确之后,会自动进行开始推送

完成pull
进入到GitHub,查看刚刚的推送。

点击
Create pull requets
发起请求。完成本次试验全部内容。

试验总结
这次试验内容是真的丰富(duo)。在此锻炼了自己敲代码的生疏的手。GitHub是个好东西,居然能够看到提交次数和提交时间。我打算写完之后,在提交一个有注释的代码。但是,我在VS2017上面写代码的时候,我看到VS好像可以直接推送到GitHub上面,还支持GitHub的登录。
从实验内容上面来说,除了学会GitHub的使用和提交,还有效能分析、回归测试这三个,其他都是在吃老本。但是我觉得很有意思的是GitHub的Bash和Linux的Bash居然是一样的操作,cd
、ls -la
这些命令居然是一模一样。但是还是得多联系,搞清楚GitHub到底怎么样使用,这次试验只是抛砖引玉,更多的还得自己去发现。我相信后面的试验只会越来越难,以后还是得多敲代码,把水平提上去,不然每周一个通宵,谁顶得住啊。最后,还是冲鸭!!!