一、需求
请用Java实现一个计算机控制台程序,要求输入俩个数和运算符,得到结果。
二、初步实现
public class Calculator {
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入操作数1:");
double number1 = scanner.nextDouble();
System.out.print("请输入操作数2:");
double number2 = scanner.nextDouble();
System.out.print("请输入运算符");
String operate = scanner.next();
String result = "";
switch (operate) {
case "+":
result = number1 + number2 + "";
break;
case "-":
result = number1 - number2 + "";
break;
case "*":
result = number1 * number2 + "";
break;
case "/":
if(number2 != 0)
result = number1 / number2 + "";
else
result = "除数不能为0!";
break;
default:
result = "操作符输入错误!";
break;
}
System.out.println("运算结果:" + result);
}catch (Exception e){
System.out.println("发生错误"+e.getMessage());
}
}
}
三、反思
这种实现方式和面向过程思路是一样的,完全没有涉及面向对象的任何特性。同时,写出的程序不容易维护,不容易扩展,更不容易复用。
何谓可维护、可扩展、可复用、灵活性好
- 可维护:当程序要改动时,只需要更改需要改动的地方,其他部分无需动作;
- 可扩展:程序需要添加新的功能,可在原基础上直接添加即可;
- 可复用:此程序实现的功能在其他的地方也可以用;
- 灵活性好:程序更改移动极为灵活,不受太多限制。
面向对象程序设计
通过面向对象的封装、继承、多态把程序的耦合度降低,用设计模式使得程序更加的灵活,容易修改,便于复用。
四、改进措施
进行封装
计算机程序分为用户的输入操作以及逻辑运算俩部分,将这俩部分进行分离:
- 运算类
public class Operation {
public static double getResult(double number1, double number2, String operate){
double result = 0.0;
switch (operate) {
case "+":
result = number1 + number2;
break;
case "-":
result = number1 - number2;
break;
case "*":
result = number1 * number2;
break;
case "/":
result = number1 / number2;
break;
}
return result;
}
}
- 用户操作类
public class Calculator {
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入操作数1:");
double number1 = scanner.nextDouble();
System.out.print("请输入操作数2:");
double number2 = scanner.nextDouble();
System.out.print("请输入运算符");
String operate = scanner.next();
String result = Operation.getResult(number1, number2, operate) + "";
System.out.println("运算结果:" + result);
}catch (Exception e){
System.out.println("发生错误"+e.getMessage());
}
}
}
封装完毕,实现运算与输入的分离,这样运算类在其他任何计算机应用程序中我们都可以直接使用,实现可复用。现在,当需要给程序添加其他运算符时,则需要增加switch分支,但是这种方式,却需要加减乘除全部参与编译,并不好。可能这么说觉得没什么说服力,具体看书P8对话。
继承多态
将所有运算符的共同特点抽取出来,并写成基类形式:
public abstract class Operation {
private double number1 = 0;
private double number2 = 0;
public double getNumber1() {
return number1;
}
public void setNumber1(double number1) {
this.number1 = number1;
}
public double getNumber2() {
return number2;
}
public void setNumber2(double number2) {
this.number2 = number2;
}
public abstract double getResult();
}
其他运算符通过继承的方式来编写,例如加法:
public class OperationAdd extends Operation{
@Override
public double getResult() {
return getNumber1()+getNumber2();
}
}
这里就是用了继承的特性,对于如何创建这些运算类的实例对象,则需要使用多态的特性。至于创建哪个运算类实例对象,至于将来会不会增加运算类,比如开根号,这是极其容易变化的地方,应该考虑单独一个类帮助我们实例化对象,这就是工厂模式。
五、简单工厂模式
先看代码实现:
public class OptFactory {
public static Operation createOperate(String operate){
Operation operation = null;
switch (operate){
case "+":
operation = new OperationAdd();
break;
case "-":
operation = new OperationSub();
break;
case "*":
operation = new OperationMul();
break;
case "/":
operation = new OperationDiv();
break;
}
return operation;
}
}
通过提供运算符,工厂构造出对应的运算类实例,通过多态的方式,返回父类引用。最后用户操作这样实现即可。后期我们想要继续增加开根号运算,我们仅需要再写一个开根号运算类继承自Operation类,然后更改工厂类添加生成实例代码。如果需要更改某个运算类的功能,也是十分容易做到的事情,只需更改其中一个类,其他毋须任何变动。
public class Calculator {
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入操作数1:");
double number1 = scanner.nextDouble();
System.out.print("请输入操作数2:");
double number2 = scanner.nextDouble();
System.out.print("请输入运算符");
String operate = scanner.next();
Operation operation = OptFactory.createOperate(operate);
operation.setNumber1(number1);
operation.setNumber2(number2);
String result = operation.getResult() + "";
System.out.println("运算结果:" + result);
}catch (Exception e){
System.out.println("发生错误"+e.getMessage());
}
}
}