一、举例
做一个非常简单的计算机,实现加减乘除运算即可,大家自然而然的会写出如下代码
1 public static void Main(String[] args) { 2 Scanner scanner = new Scanner(System.in); 3 System.out.println("请输入数字A:"); 4 double strNumA = scanner.nextDouble(); 5 System.out.println("请选择运算符号(+、-、*、/、)"); 6 String strOperate = scanner.next(); 7 System.out.println("请输入数字C:"); 8 double strNumB = scanner.nextDouble(); 9 double strResult = 0;10 if ("+".equals(strOperate)) {11 strResult = strNumA + strNumB;12 }13 if ("-".equals(strOperate)) {14 strResult = strNumA - strNumB;15 }16 if ("*".equals(strOperate)) {17 strResult = strNumA * strNumB;18 }19 if ("/".equals(strOperate)) {20 strResult = strNumA / strNumB;21 }22 System.out.println("结果是:" + strResult);23 }
二,优化
1,第一步
①由于在判断运算符时,用的是if语句,这意味着每个条件都需要做判断,相当于计算机做了三次无用功。
②没有输入校验,例如,除数不能为零的问题等等
就上述两个问题,做如下修改:
1 public static void Main(String[] args) { 2 { 3 Scanner scanner = new Scanner(System.in); 4 System.out.println("请输入数字A:"); 5 double strNumA = scanner.nextDouble(); 6 System.out.println("请选择运算符号(+、-、*、/、)"); 7 String strOperate = scanner.next(); 8 System.out.println("请输入数字C:"); 9 double strNumB = scanner.nextDouble();10 double strResult = 0;11 switch (strOperate)12 {13 case "+":14 strResult = strNumA + strNumB;15 break;16 case "-":17 strResult = strNumA - strNumB;18 break;19 case "*":20 strResult = strNumA * strNumB;21 break;22 case "/":23 if (strNumB != 0)24 {25 strResult = strNumA / strNumB;26 }27 else28 {29 System.out.println("除数不能为0");30 }31 break;32 }33 System.out.println("结果是:" + strResult);34 }
2、第二步
①上述写的简单的计算器仅仅体现了面向过程的编程,没有体现面向对象的编程
②上述代码使用控制台应用实现的,假如有一天我需要用Web 等实现一模一样的需求,那么,上述代码则需要重新编写,好可怕。
就上述问题,做如下修改:(将业务逻辑与界面分离)
Operation运算类
1 public class Operation 2 { 3 public static double getResult(double numA, double numB, String strOperate) 4 { 5 double result = 0; 6 switch (strOperate) 7 { 8 case "+": 9 result = numA + numB;10 break;11 case "-":12 result = numA - numB;13 break;14 case "*":15 result = numA * numB;16 break;17 case "/":18 result = numA / numB;19 break;20 }21 return result;22 }23 }
客户端
1 public static void Main(String[] args) { 2 { 3 try 4 { 5 Scanner scanner = new Scanner(System.in); 6 System.out.println("请输入数字A:"); 7 double strNumA = scanner.nextDouble(); 8 System.out.println("请选择运算符号(+、-、*、/、)"); 9 String strOperate = scanner.next();10 System.out.println("请输入数字C:");11 double strNumB = scanner.nextDouble();12 double strResult = 0;13 strResult =Operation.getResult(strNumA, strNumB, strOperate);14 System.out.println("结果是:" + strResult);15 }16 catch (Exception ex)17 {18 System.out.println("您的输入有错:"+ex.getMessage());19 }20 }
这样的话,无论是控制台,还是WEB以及其他应用,只需要调用 Operation 这个类即可了。实现了业务逻辑与界面的分离。这里,也用到了面向对象编程的三大特性之一的封装。
3、第三步
①如果我想增加一种计算方式,例如开根号(sqrt)运算怎么办,只能是修改Operation类,在switch中增加一种情况。
②针对①问题做修改的话,那么另一个问题就来了,我修改Oeration类的时候,之前写好的加减乘除功能全在其中,如果我不小心,或者有意搞破坏,将本来运行的好好的加减乘除功能改掉,怎么办?(此例中仅仅是计算器,如果换做是成熟的产品,或者涉及到资金运算等等的代码,运行的好好的,不可能会让程序员在其中胡作非为的)
针对上述问题,作如下修改:
我可以将加减乘除各种运算分别封装到不同的类里面,这样,就能解决②的问题,每增加一种运算,我就增加一个类,这样①问题也解决了。
首先,将不同的运算抽象出一个共同的类,即父类
1 public class Operation { 2 private double numberA; 3 private double numberB; 4 5 public double getNumberA() { 6 return numberA; 7 } 8 9 public void setNumberA(double numberA) {10 this.numberA = numberA;11 }12 13 public double getNumberB() {14 return numberB;15 }16 17 public void setNumberB(double numberB) {18 this.numberB = numberB;19 }20 21 public double getResult() {22 double result = 0;23 return result;24 }25 26 }
其次,让不同的运算继承这个父类,然后根据不同的运算,重写父类中的GetResult方法
1 // 加法类 2 public class OperationAdd extends Operation { 3 @Override 4 public double getResult() { 5 double result = 0; 6 result = numberA + numberB; 7 return result; 8 } 9 }10 11 // 减法类12 public class OperationSub extends Operation {13 @Override14 public double getResult() {15 double result = 0;16 result = numberA - numberB;17 return result;18 }19 }20 21 // 乘法类22 public class OperationMul extends Operation {23 @Override24 public double getResult() {25 double result = 0;26 result = numberA * numberB;27 return result;28 }29 }30 31 // 除法类32 public class OperationDiv extends Operation {33 @Override34 public double getResult() {35 double result = 0;36 if (numberB == 0) {37 System.out.println("除数不能为0");38 }39 result = numberA / numberB;40 return result;41 }42 }
4、第四步
到了简单工厂最核心的地方了。
这么多的类,客户端该如何用这些类呢,换句话说,客户端如何实例化这些类呢?那么,就需要一个核心的东西——工厂,这个工厂负责给客户端提供他想要的类的实例。我想要实例化什么类,告诉工厂就可以了。
代码如下:
1 public class OperationFactory 2 { 3 public static Operation createOperate(String operate) 4 { 5 Operation oper = null; 6 switch (operate) 7 { 8 case "+": 9 oper = new OperationAdd();10 break;11 case "-":12 oper = new OperationSub();13 break;14 case "*":15 oper = new OperationMul();16 break;17 case "/":18 oper = new OperationDiv();19 break;20 }21 return oper;22 }23 }
注意:这个工厂中的方法,返回的是加减乘除这些类的父类.
制造类实例的工厂有了,那么,客户端只需要告诉工厂,给我造一个什么类的实例,然后用这个实例就可以了。
客户端代码如下:
1 public static void Main(String[] args) 2 { 3 Operation oper; 4 //告诉工厂,给我一个加法类的实例 5 oper = OperationFactory.createOperate("+"); 6 oper.setNumberA(1); 7 oper.setNumberB(2); 8 double result = oper.getResult(); 9 System.out.println(result);10 }
经过上述一系列的修改,也就形成了简单工厂模式。
三、总结
简单工厂模式,即 通过一个‘工厂类’,用于子类返回父类类型或接口类型。
简单工厂模式结束,下一次,将讲解复杂工厂模式。