摘要:
1、第一阶段目标:重构四则运算-- 能把计算的功能封装起来,通过API 接口调用计算方法。定义一个计算核心类:把四则运算的计算功能包装在一个模块中 (这个模块可以是一个类 Class, 一个DLL等等)。“计算核心”模块和调用类它的其他模块之间是什么关系呢? 它们要通过一定的API (Application Programming Interface) 来和其他模块交流。这个API 接口应该怎么设计呢? 可以从下面的最简单的接口开始:Calc()
这个Calc 函数接受字符串的输入(字符串里就是运算式子,例如 “ 5+3.5“, “7/8 – 3/8 ”, “3 + 90 * (-0.3)“ 等等),这个模块的返回值是一个字符串,例如,前面几个例子的结果就是 ( ”17.5“, “ 1/2”, “-24“).
2 第二阶段目标 - 通过测试程序和API 接口测试其简单的加减乘除功能。并能看到代码覆盖率。可以扩展 Calc() 的定义,让它接受一个新的参数 “precision”, 或者可以启用一个新的函数 Setting()。最多4 个运算符数值范围是 -1000 到 1000精度是小数点后两位怎么通过API 告诉我们的模块呢? 我们当然可以用函数的参数直接传递,但是参数的组合很多,怎么定义好参数的规范呢? 建议大家考虑用 XML 来传递这些参数。增加了新的Setting() 函数之后,要让模块支持这样的参数,同时,还要保证原来的各个测试用例继续正确地工作。
3第三阶段目标 – 定义异常处理。如果输入是有错误的,例如 “1 ++ 2”, 在数值范围是 -1000 .. 1000 的时候,传进去 “10000 + 32768 * 3”, 或者是 “ 248.04 / 0” 怎么办? 怎么告诉函数的调用者 “你错了”? 把返回的字符串定义为 “-1” 来表示? 那么如果真的计算结果是 “-1” 又怎么处理呢?建议这个时候,要定义各种异常 (Exception), 让 Core 在碰到各种异常情况的时候,能告诉调用者 - 你错了! 当然,这个时候,同样要进行下面的增量修改:定义要增加什么功能 - 例如:支持 “运算式子格式错误” 异常,写好测试用例,传进去一个错误的式子,期望能捕获这个 异常。 如果没有,那测试就报错。在 Core 模块中实现这个功能,测试这个功能, 同时测试所有以前的功能,保证以前的功能还能继续工作 (没有 regression), 确认功能完成,继续下一个功能。
代码:
public String[] strOp = {"+","-","*","/","(",")"};
public boolean isOp(char c){
for(int i=0;i<op.length;i++){
if(op[i]==c){
return true;
}
}
return false;
}
public boolean isOp(String s){
for(int i=0;i<strOp.length;i++){
if(strOp[i].equals(s)){
return true;
}
}
return false;
}
/*
* 处理输入的字符串
* 将他分成一个一个的字符串
*/
public List<String> work(String str)
{
List<String> list = new ArrayList<String>();
char c;
StringBuilder sb = new StringBuilder();
for(int i=0;i<str.length();i++){
c = str.charAt(i);
if(!isOp(c)){
sb.append(c);
}
else{
if(sb.toString().length()>0){
list.add(sb.toString());
sb.delete(0, sb.toString().length());
}
list.add(c+"");
}
}
if(sb.toString().length()>0){
list.add(sb.toString());
sb.delete(0, sb.toString().length());
}
return list;
}
/*
* 输出检测
*/
public void printList(List<String> list){
for(String o:list){
System.out.print(o+" ");
}
}
*
* 中缀表达式转换成后缀表达式
*/
public List<String> translate(List<String> str)
{
List<String> list=new ArrayList<String>();
Stack<String> stack = new Stack<String>();//暂存操作符
for(int i=0;i<str.size();i++)
{
String s=str.get(i);
if(s.equals("(")){
stack.push(s);
}else if(s.equals("*")||s.equals("/")){
stack.push(s);
}else if(s.equals("+")||s.equals("-"))
{
if(s.equals("-")&&stack.peek().equals("("))
{
i++;
list.add("-"+str.get(i));
continue;
}
if(!stack.empty())
{
while(!(stack.peek().equals("(")))
{
list.add(stack.pop());
if(stack.empty())
{
break;
}
}
stack.push(s);
}
else
{
stack.push(s);
}
}
else if(s.equals(")"))
{
while(!(stack.peek().equals("(")))
{
list.add(stack.pop());
}
stack.pop();
}
else
{
list.add(s);
}
if(i==str.size()-1)
{
while(!stack.empty())
{
list.add(stack.pop());
}
}
}
return list;
}
* 后缀表达式的计算
*/
public Double docal(List<String> list)
{
Stack<Double> stack=new Stack<Double>();
for(int i=0;i<list.size();i++)
{
String s = list.get(i);
Double t=0.0;
if(!isOp(s))
{
t =Double.parseDouble(s);
stack.push(t);
}
else
{
if(s.equals("+"))
{
Double a1 = stack.pop();
Double a2 = stack.pop();
Double v = a2+a1;
stack.push(v);
}
else if(s.equals("-"))
{
Double a1 = stack.pop();
Double a2 = stack.pop();
Double v = a2-a1;
stack.push(v);
}
else if(s.equals("*"))
{
Double a1 = stack.pop();
Double a2 = stack.pop();
Double v = a2*a1;
stack.push(v);
}
else if(s.equals("/"))
{
Double a1 = stack.pop();
Double a2 = stack.pop();
Double v = a2/a1;
stack.push(v);
}
}
}
return stack.pop();
}
}
// TODO Auto-generated method stub
Scanner in=new Scanner(System.in);
Cal cal=new Cal();
System.out.println("请输入一个计算式:");
String str=in.next();
List<String> list=cal.work(str);
List<String> list2=cal.translate(list);
/*cal.printList(list);
System.out.println();
cal.printList(list2);
System.out.println();*/
System.out.println(cal.docal(list2));
}
结果: