从一个简单的控制台计算器程序开始,编写程序在控制台输入两个运算数和操作符,完成加减乘除运算。
面向过程风格
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import java.util.Scanner;
public class Calculator { private static Scanner scan;
public static void main(String[] args) { try { scan = new Scanner(System.in); System.out.println("请输入数字A"); double a = scan.nextDouble(); System.out.println("请输入运算符,包括+-*/:"); String op = scan.next(); System.out.println("请输入数字B"); double b = scan.nextDouble(); switch (op) { case "+": System.out.println("计算结果为"+(a+b)); break; case "-": System.out.println("计算结果为"+(a-b)); break; case "*": System.out.println("计算结果为"+(a*b)); break; case "/": if (b==0) { throw new Exception("被除数不能为0"); }else{ System.out.println("计算结果为"+(a/b)); } break; default: System.out.println("输入运算符有误"); break; } } catch (Exception e) { e.printStackTrace(); } } }
|
以上代码虽然实现了计算器功能,但是不够灵活,可复用、可扩展、可维护性能并不好,如果能够将界面和业务分离,把计算功能抽象出来,就能复用到不同的界面,例如web端、移动端等,于是就有了第二个版。
业务逻辑封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class Operation { private double num1; private double num2; private double num3; private String op; public Operation(double num1,double num2,String op){ this.num1=num1; this.num2=num2; this.op=op; } public double cal(){ try { switch (op) { case "+": num3=num1+num2; break; case "-": num3=num1-num2; break; case "*": num3=num1*num2; break; case "/": if (num2==0) { throw new Exception("被除数不能为零"); } num3=num1/num2; break; default: throw new Exception("操作符输入有误"); } } catch (Exception e) { e.printStackTrace(); } return num3; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import java.util.Scanner;
public class Enter { private static Scanner scan; public static void main(String[] args) { scan = new Scanner(System.in); System.out.println("请输入数字A"); double a = scan.nextDouble(); System.out.println("请输入运算符,包括+-*/:"); String op = scan.next(); System.out.println("请输入数字B"); double b = scan.nextDouble(); Operation o1 = new Operation(a, b, op); System.out.println("计算结果为"+o1.cal()); } }
|
面向对象三大特性封装继承多态,上述代码只用到了封装特性,虽然将业务和界面分离,但是业务逻辑的代码依然没有实现很好的分离,无法应对更多的需求,例如:
- 计算类中的不同计算方法并未分离,当只需要执行一种运算时,其他运算也不可避免的参与了编译
- 当需要增加计算方法时要求拥有计算类的修改权限
基于以上缺陷,有了面向对象风格的第三个版本。
面向对象风格
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Operation { private double num1; private double num2; private double num3; public Operation(double num1, double num2) { super(); this.num1 = num1; this.num2 = num2; } public double getNum1() { return num1; } public double getNum2() { return num2; } public double cal(){ return num3; } }
|
1 2 3 4 5 6 7 8 9 10 11
| public class OperateAdd extends Operation{ public OperateAdd(double num1, double num2) { super(num1, num2); }
public double cal(){ return this.getNum1()+this.getNum2(); } }
|
1 2 3 4 5 6 7 8 9
| public class OperateMinus extends Operation{ public OperateMinus(double num1, double num2) { super(num1, num2); }
public double cal() { return this.getNum1()-this.getNum2(); } }
|
1 2 3 4 5 6 7 8 9
| public class OperateMultiply extends Operation{ public OperateMultiply(double num1, double num2) { super(num1, num2); }
public double cal() { return this.getNum1()+this.getNum2(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class OperateDivide extends Operation{ public OperateDivide(double num1, double num2) { super(num1, num2); }
public double cal() { try { if (this.getNum2()==0) { throw new Exception("被除数不能为零"); } } catch (Exception e) { e.printStackTrace(); System.exit(0); } return this.getNum1()/this.getNum2(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import java.util.Scanner;
public class Enter { private static Scanner scan; private static Operation o; public static void main(String[] args) { try { scan = new Scanner(System.in); System.out.println("请输入数字A"); double a = scan.nextDouble(); System.out.println("请输入运算符,包括+-*/:"); String op = scan.next(); System.out.println("请输入数字B"); double b = scan.nextDouble(); switch (op) { case "+": o = new OperateAdd(a, b); break; case "-": o = new OperateMinus(a, b); break; case "*": o = new OperateMultiply(a, b); break; case "/": o = new OperateDivide(a, b); break; default: throw new Exception("输入运算符有误"); } System.out.println("计算结果为"+o.cal()); } catch (Exception e) { e.printStackTrace(); } } }
|
上述代码充分利用了面向对象的封装继承和多态原则,通过子类对父类的继承和子类实例化时对象上转型,保证每次运算不用编译额外的运算过程,提高了代码的效率,提升了业务逻辑的可扩展性,当需求变化要加入新的运算时只需写入新的子类,继承计算父类并覆盖父类的计算方法即可。
简单工厂模式
实际上上一个面向对象的版本已经出现了简单工厂模式的雏形,只需要把界面中的实例化过程进一步封装就符合了简单工厂模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class OperationFactory { public static Operation createOperation(String op){ Operation o = null; try { switch (op) { case "+": o = new OperateAdd(); break; case "-": o = new OperateMinus(); break; case "*": o = new OperateMultiply(); break; case "/": o = new OperateDivide(); break; default: throw new Exception("输入运算符有误"); } } catch (Exception e) { e.printStackTrace(); System.exit(0); } return o; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class Operation { private double num1; private double num2; private double num3;
public double getNum1() { return num1; }
public void setNum1(double num1) { this.num1 = num1; }
public double getNum2() { return num2; }
public void setNum2(double num2) { this.num2 = num2; }
public double cal(){ return num3; } }
|
1 2 3 4 5
| public class OperateAdd extends Operation{ public double cal(){ return this.getNum1()+this.getNum2(); } }
|
1 2 3 4 5
| public class OperateMinus extends Operation{ public double cal() { return this.getNum1()-this.getNum2(); } }
|
1 2 3 4 5
| public class OperateMultiply extends Operation{ public double cal() { return this.getNum1()+this.getNum2(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class OperateDivide extends Operation{ public double cal() { try { if (this.getNum2()==0) { throw new Exception("被除数不能为零"); } } catch (Exception e) { e.printStackTrace(); System.exit(0); } return this.getNum1()/this.getNum2(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import java.util.Scanner;
public class Enter { private static Scanner scan; public static void main(String[] args) { try { scan = new Scanner(System.in); System.out.println("请输入数字A"); double a = scan.nextDouble(); System.out.println("请输入运算符,包括+-*/:"); String op = scan.next(); System.out.println("请输入数字B"); double b = scan.nextDouble(); Operation o = OperationFactory.createOperation(op); o.setNum1(a); o.setNum2(b); System.out.println("计算结果为"+o.cal()); } catch (Exception e) { e.printStackTrace(); } } }
|