很多人在学习编程的时候都会被老师指导学习画一个计算器的界面,但是都并没有实现它的功能。这个看起来在常人的眼里是小得不能再小的计算工具,要做起来其实一点都不简单。计算器最难的地方,就难在于它的逻辑。如果你仅仅考虑的只有一个和另一个数之间的运算,那我只能告诉你,现阶段的你只能是个程序员,一点都不具备软件工程师的素养。做计算器之前没有分析好,你会觉得越做越乱,没有方向感。于是,你或许会在上网上查找一些案例,结果发现他们所共享出来的东西并不是那么完善。
网上很多例子都是直接按照正常人的思路去做这个小小的计算器,但是事实上,我们生活当用会有很多非正常的操作。而软件工程师除了要想怎么用正常操作能实现这些功能的同时,更多的要去向那些非正常态的操作,也就是所谓的异常处理。你看看自己的计算器有没有考虑到用户按下N1+NI==的情况得出来的是什么数字?有没有考虑到用户按下N1+-N*的情况下又是什么数字?或者是更复杂的N1+N2*N3/*+=又是什么数字?想成为一名软件工程师,你必须学会去想这些问题,分析完毕,才去实现每一个功能。当你能做出一个别人异常操作搞不死你的软件/系统,你便是一个及格的软件工程师。
当然,对于计算器,完整功能的计算器,搞不死的计算器的源代码,我是不会共享的。我只会把我设计的思想分享给你。怎么说,你也没看见什么完整工程的计算器的源代码,可能是很多人做这个都是卖它作为某些机器的预设置的软件,卖那种软件是很赚钱的,别人每生产一部机器都要给你付钱。但是要做到能够作为机器的预设置软件,一点都不简单。
以Windows默认自带的计算器为例,也是最常用的实体计算器,只是用软件形式存在罢了。要分析设计的内容包括如下:
1. 数字的精度和溢出的问题。刚刚开始可以用double类型去做,但是算到比较大的数字的时候,你会发现它并不会以科学计数法的方式去显示这些数字,而是变成了一个极小的小数。所以,不应该用double,而要用BigDecimal。double类型的数据特点是小数部分的精度高,但不代表它的整数部分精度高,它的精度明显不够是在做比较大的整数的乘法运算特别明显不正确。当超过你所设定的字符长度不能再计算溢出,则不能再进行计算。实现方案对整个数字段判断,当最后一位为E的时候就不能再进行计算。当然,你也可以做成不涉及到数据溢出。
2. 后退键的使用,只要是按下了计算运算符,后退键都不能工作。使用String类型对整个数字段从尾端进行删减。
if(isCount){
if(isFirstClicked && !isEqualClicked){
//当输入框为一个位数,0时候,显示为0
if(num.getText().length()==1|| num.getText().toString()=="0."){
num.setText("0");
isFirstClicked = false;
//否则将输入框的数字从尾部减去一位
}else{
String oldNum = num.getText().toString();
StringnewNum = oldNum.substring(0, oldNum.length()-1);
num.setText(newNum);
isFirstClicked = true;
}
}
}
3. 小数点的控制,要检查只能出现一个小数点(android版的不需要监控这个,只要把EditText的inputtype设置为number,android的库自动控制)。
4. 计算平方根的数不能为负数,除法运算除数不能为0,这类的非法都要输出提示。
5. MS记录数字,当这个记录的数字为0的时候,则不会再保存这个记录。
6. 设置一个int类型的变量足以分辨四种基本运算符,用于判断用户想做什么运算。
7. 有4个boolean要定义的:
a) 定义一个变量,标记计算器是否能在正常情况下运算。例如,用户的一些非法操作对负数开平方,或者是数据溢出,则不能继续再计算。
b) 定义一个变量,标记数字键是不是第一次被按下,从数字段被第一次按下而记录这数字到底是第一个操作数还是第二个操作数。当然,也有可能只出现一个操作数,也就是用户按下N1+=的情况。
c) 定义一个变量,标记是否按下了运算符,从而控制后退键是否能操作。
d) 定义一个变量,标记等是否被点击过,用于控制后退键是否能操作。
8. 按下数字键,我选择把它们封装到一个方法中:
//按下数字键盘
public voidclickNumber(CharSequence i){
if(isCount){
if(isFirstClicked == false){
isFirstClicked = true;
num.setText(i);
}else{
num.append(i);
}
}
}
例如按下1键,实现则:clickNumber(“1”);
要注意的是0和小数点并不能用这个通用的方法,要另外设计。0在没有小数点时候不能再添加0。
9. 在没有按下任何运算符前提下,按下等号等于数据本身。
10. 判断数据是否溢出,看看数据的最后一位是否为E:
//判断是数据是否溢出
public void judeCount(){
Stringstr = num.getText().toString();
if(str.indexOf("E")==(str.length()-1)){
isCount = false;
}
}
11. 还有个溢出问题要注意的是在1/x运算的时候,可能要添加负号运算,此时可能会出现数字格式无法转换异常。
12. 最难的逻辑在对运算符的判断,就是用户按下N1+=的时候,N1+N2-N3=的时候,N1+N2+/*N3-+的时候等等。例如上述提到的N1+=,在逻辑上应该转换为N1+N1=;N1+N2+/*N3-+的时候,在逻辑上应该转换成N1+N2*N3+。(我发现我用的手机HTC的G8默认的计算器有bug。如果你们有这款软件,你们可以试试按下N1/*=,它的结果并不是N1*N1。你随便拿一个实体的计算器按下N1/*=,结果一定是N1*N1,不然这个计算器是有问题的。)实现这个思路应该是在计算前要判断前面的已经按下的运算符是什么符号,在按下一个运算符时候不管是否跟先前的运算符相同,都要对上一次运算符做出相应计算。我自己做的是把这四种运算符都封装在一个函数中,要调用的时候以刚才提到定义的int 分别为1,2,3,4来判断加法,减法,乘法,除法运算。注意,在计算时候第一个按下的是运算符号,则要默认为第一个操作数为0。在运算符不为0时候,连续按下等号,是继续上一次操作运算符继续运算。
我这次做的计算器是运行在Android系统上的,apk晚点再上传给大家玩玩,因为界面做得不咋的。等界面美化好了,我再上传到各大手机软件平台给大家试用。思路都给你了,自己动手做是最好的学习方式。计算器虽小,但是android版的我都写了500多行代码,量还是蛮大的。大家加油,如果有更好的思路,欢迎交流。
如果你对以上内容还有什么不明白的地方,欢迎Email给我学习交流,但不要问我拿源代码。
Email Address: arjinmc@sina.com