需求:使用Java实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果。
public static void version1() {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数字A:");
int A = scanner.nextInt();
System.out.println("请输入数字B:");
int B = scanner.nextInt();
System.out.println("请输入运算符号(+、-、*、/):");
String oper = scanner.next();
int result = 0;
if (oper.equals("+")) { // 问题1:分支判断写法不好,计算机做了3次无用功
result = A + B;
}
if (oper.equals("-")) {
result = A - B;
}
if (oper.equals("*")) {
result = A * B;
}
if (oper.equals("/")) {
result = A / B; // 问题2:如果除数时输入0如何处理,输入的是字符符号不是数字如何处理
}
System.out.println("结果是:" + result);
}
存在的问题:
public static void version2() {
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数字A:");
int A = scanner.nextInt();
System.out.println("请输入数字B:");
int B = scanner.nextInt();
System.out.println("请输入运算符号(+、-、*、/):");
String oper = scanner.next();
int result = 0;
switch (oper) {
case "+":
result = A + B;
break;
case "-":
result = A - B;
break;
case "*":
result = A * B;
break;
case "/":
if (B != 0) {
result = A / B;
} else {
throw new IllegalArgumentException("除数不能为0");
}
break;
}
System.out.println("结果是:" + result);
} catch (Exception e) {
System.out.println("您的输入有误:" + e.getMessage());
}
}
上述只是实现功能,但其实是用计算机的方式去思考。比如程序要求输入两个数和运算符号,然后根据运算符号判断选择如何运算,得到结果,这本身没有错。但这样的思维却使得我们的程序只为满足实现当前的需求,程序不容易【维护】,不容易【扩展】,更不容易【复用】,从而达不到高质量的要求。
需求:要求再写一个Windows的计算器,上述的代码能否复用呢?
当代码中重复的代码多到一定程度的时候,维护的时候可能就是一场灾难。 越大的系统问题越严重,编程有一原则,用尽可能的办法去避免重复,考虑哪些是和计算器有关的,哪些是和控制台无关的。让业务逻辑与界面逻辑分开,让它们之间的耦合度下降。
/**
* 运算类(Operation):
* 在Windows程序、Web版程序、PDA、手机等需要移动系统的软件需要运算都可以用它。
*/
public class Operation {
public static double getResult(double A, double B, String operate) {
double result = 0d;
switch (operate) {
case "+":
result = A + B;
break;
case "-":
result = A - B;
break;
case "*":
result = A * B;
break;
case "/":
result = A / B;
break;
}
return result;
}
}
客户端代码:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数字A:");
int A = scanner.nextInt();
System.out.println("请输入数字B:");
int B = scanner.nextInt();
System.out.println("请输入运算符号(+、-、*、/):");
String oper = scanner.next();
double result = Operation.getResult(A, B, oper);
System.out.println("结果是:"+result);
}
问:如果我希望增加一个开根运算,如何修改?
答:只需要改Operation类就行了,在switch中加一个分支就行了。
问题是要加一个平方根运算,却需要让加减乘除的运算都参与编译,如果不小心将加法改成了减法,岂不是很糟糕。本来让你加一个功能,却让运行良好的功能代码发生了变化,这个风险太大了。所以应该将加减乘除等运算分离,修改其中要给不影响另外的几个,增加运算算法也不影响其他代码。
public abstract class Operation {
private double numberA = 0;
private double numberB = 0;
/**
* 子类实现运算操作
*/
public abstract double getResult();
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;
}
}
// 加
public class OperationAdd extends Operation {
@Override
public double getResult() {
return getNumberA() + getNumberB();
}
}
// 减
public class OperationSub extends Operation {
@Override
public double getResult() {
return getNumberA() - getNumberB();
}
}
// 乘
public class OperationMul extends Operation {
@Override
public double getResult() {
return getNumberA() * getNumberB();
}
}
// 除
public class OperationDiv extends Operation {
@Override
public double getResult() {
if (getNumberB() == 0) {
throw new IllegalArgumentException("除数不能为0");
}
return getNumberA() / getNumberB();
}
}
如何让计算器知道我希望使用哪一种算法呢?使用简单工厂模式。
到底要实例化谁,将来会不会增加实例化的对象,比如增加开根运算,
这是很容易变化的地方,应该考虑用一个单独的类来做这个创造实例的过程,这就是工厂。
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;
}
}
客户端类:
只需要输入运算符号,工厂就实例化出合适的对象,通过多态,返回父类的方式实现了计算器的结果
如果要修改:1:增加运算子类 2:在工厂类中增加switch分支
public static void main(String[] args) {
Operation oper= OperationFactory.createOperate("+");
oper.setNumberA(1);
oper.setNumberB(2);
double result = oper.getResult();
System.out.println(result);
}