精彩的代码是如何想出来的,要比看到精彩的代码更加令人期待。 ——程杰
首先我们给出一段简单的计算器程序代码:
import java.util.Scanner;
public class Program {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入数字A:");
double numberA=scanner.nextDouble();
System.out.println("请选择运算符号(+、-、*、/):");
String strOperate=scanner.next();
System.out.println("请输入数字B:");
double numberB=scanner.nextDouble();
double result=0;
switch(strOperate) {
case "+":
result=numberA+numberB;
break;
case "-":
result=numberA-numberB;
break;
case "*":
result=numberA*numberB;
break;
case "/":
if(numberB!=0)
result=numberA/numberB;
else
System.out.println("除数不能为0!");
break;
}
System.out.println("结果是:"+result);
scanner.close();
}
}
在这个程序中,先要求输入两个数和运算符号,然后根据运算符号判断选择如何计算,得到结果。这就是我们用计算机理解的逻辑来描述和表达待解决的问题及具体的求解过程,但这样的思维使得程序不易维护、不易扩展、不易复用。
优秀程序的四个特性:
- 可维护
- 可复用
- 可扩展
- 灵活性好
面向对象的三大特征:封装、继承、多态
业务的封装
第一次改进:让业务逻辑与界面逻辑分开,让它们之间的耦合度降低,只有分离开,才可以达到容易扩展和维护。
Operation运算类:
public class Operation {
public static double getResult(double numberA,double numberB,String operate) {
double result=0;
switch(operate) {
case "+":
result=numberA+numberB;
break;
case "-":
result=numberA-numberB;
break;
case "*":
result=numberA*numberB;
break;
case "/":
if(numberB!=0)
result=numberA/numberB;
else
System.out.println("除数不能为0!");
break;
}
return result;
}
}
客户端代码:
import java.util.Scanner;
public class Program1 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("请输入数字A:");
double numberA=scanner.nextDouble();
System.out.println("请选择运算符号(+、-、*、/):");
String strOperate=scanner.next();
System.out.println("请输入数字B:");
double numberB=scanner.nextDouble();
double result=Operation.getResult(numberA,numberB,strOperate); //调用运算类的getResult方法
System.out.println("结果是:"+result);
}
}
紧耦合vs松耦合
考虑一个问题:增加一个开跟号运算,如何修改?
修改Operation类,在switch中增加分支即可。但这需要让加减乘除的运算都来参与编译,若在修改中不小心修改了这些已编译好的代码就糟糕了。
第二次改进:把加减乘除等运算分离,这样修改其中一个不影响其他的,增加运算代码也不会影响已有的运算。(使用继承和多态)
Operation运算类:定义getResult()抽象方法,在加减乘除子类中实现
public abstract class Operation {
private double numberA; //面向对象编程中,不允许外界直接对类的成员变量直接访问
private double numberB; //通过get、set方法来访问私有成员变量
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 abstract double getResult(); //定义抽象方法,在子类中实现
}
加减乘除类:
class OperationAdd extends Operation { //加法类
public double getResult() {
double result;
result=getNumberA()+getNumberB();
return result;
}
}
class OperationSub extends Operation { //减法类
public double getResult() {
double result;
result=getNumberA()-getNumberB();
return result;
}
}
class OperationMul extends Operation{ //乘法类
public double getResult() {
double result;
result=getNumberA()*getNumberB();
return result;
}
}
class OperationDiv extends Operation{ //除法类
public double getResult() {
double result=0;
if(getNumberB()!=0)
result=getNumberA()/getNumberB();
else
System.out.println("除数不能为0!");
return result;
}
}
简单工厂模式
问题:如何实例化对象
第三次改进:考虑用一个单独的类来做创造实例的过程即工厂。
简单运算工厂类:
public class OperationFactory {
//输入运算符号,实例化出相应的对象
public static Operation createOperate(String operate) { //返回值为Operation对象
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;
}
}
客户端代码:
import java.util.Scanner;
public class Program {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
Operation oper;
System.out.println("请选择运算符号(+、-、*、/):");
String strOperate=scanner.next();
oper=OperationFactory.createOperate(strOperate); //创建相应的运算类的对象
System.out.println("请输入数字A:");
oper.setNumberA(scanner.nextDouble());
System.out.println("请输入数字B:");
oper.setNumberB(scanner.nextDouble());
double result=oper.getResult(); //调用相应运算类中的getResult函数
System.out.println("结果是:"+result);
scanner.close();
}
}
经过上述修改后,以后若要修改加法运算,只需要修改OperationAdd类即可;若要求平方根、立方根、自然对数等其他的运算,只需要添加相应的子类即可,然后修改运算工厂类,在switch中增加该运算的分支。
这几个类之间的关系如下图所示: