面试题:
请使用JAVA面向对象语言实现一个计算器控制台程序
我们来看下面一段代码:
/**
* 请使用JAVA面向对象语言实现一个计算器控制台程序
* Created by ZhuPengWei on 2018/1/24.
*/
public class OriginalCode {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入数字A");
Integer A = sc.nextInt();
System.out.println("请选择运算符号(+ - * /): ");
String symbol = sc.next();
System.out.println("请输入数字B");
Integer B = sc.nextInt();
switch (symbol) {
case "+":
System.out.println("结果是:" + (A + B));
break;
case "-":
System.out.println("结果是:" + (A - B));
break;
case "*":
System.out.println("结果是:" + A * B);
break;
case "/":
if (0 == B) {
System.out.println("除数不能为0");
} else {
System.out.println("结果是:" + A / B);
}
break;
default:
System.out.println("您的输入有误");
}
}
}
}
比如计算器这个程序,先要求输入两个数和运算符号,然后根据运算符号判断选择如何运算,得到结果,这本身没有错,但这样的思维却使得我们的程序只实现当前的需求,程序不容易维护,不容易扩展,更加不容易复用,从而达不到高质量代码的要求
1. 业务的封装
准确的来说,就是让业务与界面逻辑分开,让他们的耦合度下降。只有分离开
才可以打到容易维护或者扩展
Operatation运算类
/**
* 运算类
* Created by ZhuPengWei on 2018/1/24.
*/
public class Operation {
/**
* 获取结果
*
* @param numberA 数字A
* @param numberB 数字B
* @param operate 操作运算符
* @return 结果
*/
public static double getResult(double numberA, double numberB, String operate) {
double result = 0d;
switch (operate) {
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
if (0 == numberB) {
throw new RuntimeException("除数不能为0");
} else {
result = numberA * numberB;
}
break;
default:
throw new RuntimeException("您的输入有误");
}
return result;
}
}
/**
* 客户端
* Created by ZhuPengWei on 2018/1/24.
*/
public class Client {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入数字A");
Double numberA = sc.nextDouble();
System.out.println("请选择运算符号(+ - * /): ");
String operate = sc.next();
System.out.println("请输入数字B");
Double numberB = sc.nextDouble();
// 获取计算结果
double result = Operation.getResult(numberA, numberB, operate);
System.out.println("结果是:" + result);
}
}
}
这样的代码完全的把业务和界面分离了。但是这样的代码,能否做到很灵活的可修改和可扩展呢???
2. 使用多态和继承继续改进代码
新的需求:
现在如果我想增加一个开根(sqrt)运算,如何改?
是否只是该Opration类,在switch中加一个分支就行了?
问题是要加一个平方根运算,却需要让加减乘除运算都得来参与编译,如果一不小心,更改了原有代码的逻辑,这样看起来确实是很糟糕
打个比方,如果现在公司要求你为公司的薪资管理系统做维护,原来只有技术人员(月薪),市场销售人员(底薪+提成),经理(年薪+股份)
三种运算算法,现在要增加兼职工作人员(时薪)的算法,但按照上面一种的写法,公司就必须要把包含原三种算法的运算类给你,让你修改,
你如果心中小算盘一打,“TMD,公司给我的工资这么低,我真的是很郁闷,这下有机会了”,于是你除了增加兼职算法以外,在技术人员(月薪)
算法中写了一句
if(员工是xxxx){
salary =salary* 1.1;
}
那就意味着,你的月薪每月都会增加10%(小心被抓),本来是让你增加一个功能,却使得原有的运行良好的功能代码产生了变化,这个风险太大了。
改进:首先是一个运算类,他有两个Number属性,主要用于计算器的前后数,然后有一个虚方法getResult(),用于得到结果,然后我把加减乘除都写成了
运算类的子类,继承它后,重写了getResult()方法,这样如果要修改任何一个算法,就不需要提供其他算法的代码了
/**
* 运算类
* Created by ZhuPengWei on 2018/1/24.
*/
public class Operation {
private double numberA = 0d;
private double numberB = 0d;
public double getResult() {
return 0d;
}
public double getNumberA() {
return numberA;
}
public void setNumberA(double numberA) {
this.numberA = numberA;
}
public double getNumberB() {
return numberB;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
}
/**
* 加法运算类
* Created by ZhuPengWei on 2018/1/24.
*/
public class OperationAdd extends Operation {
@Override
public double getResult() {
double result = 0d;
result = getNumberA() + getNumberB();
return result;
}
}
/**
* 减肥运算类
* Created by ZhuPengWei on 2018/1/24.
*/
public class OperationSub extends Operation {
@Override
public double getResult() {
double result = 0d;
result = getNumberA() - getNumberB();
return result;
}
}
/**
* 乘法运算类
* Created by ZhuPengWei on 2018/1/24.
*/
public class OperationMul extends Operation {
@Override
public double getResult() {
double result = 0d;
result = getNumberA() * getNumberB();
return result;
}
}
/**
* 除法运算类
* Created by ZhuPengWei on 2018/1/24.
*/
public class OperationDiv extends Operation {
@Override
public double getResult() {
double result = 0d;
result = getNumberA() / getNumberB();
return result;
}
}
3. 简单工厂模式
/**
* 简单工厂模式
* Created by ZhuPengWei on 2018/1/25.
*/
public class OperationFactory {
public static Operation createOperate(String operate) {
Operation oper = null;
switch (operate) {
case "+":
oper = new OperationAdd();
break;
case "-":
oper = new OperationSub();
break;
case "*":
oper = new OperationMul();
break;
case "/":
oper = new OperationDiv();
break;
}
return oper;
}
}
客户端代码
/**
* 客户端
* Created by ZhuPengWei on 2018/1/25.
*/
public class Client {
public static void main(String[] args) {
Operation operate;
operate = OperationFactory.createOperate("+");
operate.setNumberA(12);
operate.setNumberB(13);
System.out.println(operate.getResult());
}
}
如果我们需要增加各种复杂的运算,比如说平方根、立方根、自然对数、正弦余弦等,只需要增加响应的运算子类并且修改运算类工厂,在switch中增加分支