使用简单工厂模式实现一个计算器功能
一、过程化设计
主方法如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStreamReader; 4 5 6 public class Computer { 7 8 /** 9 * @param args 10 * @throws IOException 11 */ 12 public static void main(String[] args) throws IOException { 13 // TODO Auto-generated method stub 14 System.out.println("请输入数字1:"); 15 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 16 String strNumA = br.readLine(); 17 System.out.println("请输入运算符:"); 18 br = new BufferedReader(new InputStreamReader(System.in)); 19 String strOperator = br.readLine(); 20 System.out.println("请输入数字2:"); 21 br = new BufferedReader(new InputStreamReader(System.in)); 22 String strNumB = br.readLine(); 23 String strResult = ""; 24 try { 25 if (StringConst.Plus.equals(strOperator)) { 26 strResult = String.valueOf(Double.parseDouble(strNumA) + Double.parseDouble(strNumB)); 27 } 28 else if (StringConst.Minus.equals(strOperator)) { 29 strResult = String.valueOf(Double.parseDouble(strNumA) - Double.parseDouble(strNumB)); 30 } 31 else if (StringConst.Multiply.equals(strOperator)) { 32 strResult = String.valueOf(Double.parseDouble(strNumA) * Double.parseDouble(strNumB)); 33 } 34 else if (StringConst.Except.equals(strOperator)) { 35 if ("0".equals(strNumB)) { 36 System.out.println("除数不能为0,请检查!"); 37 return; 38 } 39 strResult = String.valueOf(Double.parseDouble(strNumA) / Double.parseDouble(strNumB)); 40 } 41 else { 42 System.out.println("您输入的运算符不正确,请检查!"); 43 return; 44 } 45 } 46 catch (NumberFormatException ex){ 47 System.out.println("您输入的数据不正确,请检查!"); 48 return; 49 } 50 catch (Exception ex) { 51 System.out.println(ex.getMessage()); 52 System.out.println("----------------------------------------"); 53 System.out.println(ex.getStackTrace()); 54 } 55 System.out.println("运算结果为:"+strResult); 56 } 57 }
常量定义如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class StringConst { 2 public static final String Plus = "+"; 3 4 public static final String Minus = "-"; 5 6 public static final String Multiply = "*"; 7 8 public static final String Except = "/"; 9 }
二、面向对象设计
下面将围绕面向对象编程三大特征:封装、继承、多态对上面代码进行优化。
1.首先使用封装对上面过程化的代码进行修改,通过封装可以将实现功能的业务逻辑与界面显示分离开来,界面只需要展示计算的结果,不需要关心如何去实现的细节,而具体是怎么计算的则交给单独的一个类去处理,从而降低了具体实现代码与界面之间的耦合,同时还可以将具体实现的代码可以应用到不同项目中,如:网站,移动平台等等,从另一方面也提高了代码的复用,也就是代码的可重用性提高了。
修改后的主方法如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStreamReader; 4 5 6 public class Computer { 7 8 /** 9 * @param args 10 * @throws IOException 11 */ 12 public static void main(String[] args) throws IOException { 13 // TODO Auto-generated method stub 14 System.out.println("请输入数字1:"); 15 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 16 String strNumA = br.readLine(); 17 System.out.println("请输入运算符:"); 18 br = new BufferedReader(new InputStreamReader(System.in)); 19 String strOperator = br.readLine(); 20 System.out.println("请输入数字2:"); 21 br = new BufferedReader(new InputStreamReader(System.in)); 22 String strNumB = br.readLine(); 23 System.out.println("运算结果为:"+ComputerHelper.getResults(strNumA, strOperator, strNumB)); 24 25 } 26 }
辅助类的类定义如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class ComputerHelper { 2 public static String getResults(String strNumA, String strOperator, String strNumB) { 3 String strResult = ""; 4 try { 5 if (StringConst.Plus.equals(strOperator)) { 6 strResult = String.valueOf(Double.parseDouble(strNumA) + Double.parseDouble(strNumB)); 7 } 8 else if (StringConst.Minus.equals(strOperator)) { 9 strResult = String.valueOf(Double.parseDouble(strNumA) - Double.parseDouble(strNumB)); 10 } 11 else if (StringConst.Multiply.equals(strOperator)) { 12 strResult = String.valueOf(Double.parseDouble(strNumA) * Double.parseDouble(strNumB)); 13 } 14 else if (StringConst.Except.equals(strOperator)) { 15 if ("0".equals(strNumB)) { 16 return "除数不能为0,请检查!"; 17 } 18 strResult = String.valueOf(Double.parseDouble(strNumA) / Double.parseDouble(strNumB)); 19 } 20 else { 21 return "您输入的运算符不正确,请检查!"; 22 } 23 } 24 catch (NumberFormatException ex){ 25 return "您输入的数据不正确,请检查!"; 26 } 27 catch (Exception ex) { 28 System.out.println(ex.getMessage()); 29 System.out.println("----------------------------------------"); 30 System.out.println(ex.getStackTrace()); 31 } 32 return strResult; 33 } 34 }
2.下面将从继承的角度来分析这个辅助类,从这个辅助类中的if条件判断中可以看出+、-、×、/这四个运算符之间所共有的属性,如:都有2个参加运算的数值和1个返回结果,因此不难想到可以建一个父类,在父类的定义中包含这2个参加运算的数值和1个返回结果的方法,而+、-、×、/可以建立成这个父类的子类,通过继承可以获得父类所定义的属性,同时还可以复写父类的方法,通过继承,可以减少开发过程中的冗余代码,避免了属性在子类中重复定义以及相同功能方法的定义,这些公共的部分都可以提取到父类当中,从而提高了代码的复用。
父类定义如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class Operator { 2 public String strNumA; 3 4 public String strNumB; 5 6 public String getResults(){ 7 return ""; 8 } 9 }
四个子类定义如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class PlusOperator extends Operator{ 2 3 public String getResults() { 4 5 String strResult = ""; 6 7 try { 8 strResult = String.valueOf(Double.parseDouble(strNumA) + Double.parseDouble(strNumB)); 9 } 10 catch (NumberFormatException ex){ 11 return "您输入的数据不正确,请检查!"; 12 } 13 catch (Exception ex) { 14 System.out.println(ex.getMessage()); 15 System.out.println("----------------------------------------"); 16 System.out.println(ex.getStackTrace()); 17 } 18 19 return strResult; 20 } 21 } 22 23 24 public class MinusOperator extends Operator{ 25 26 public String getResults() { 27 28 String strResult = ""; 29 30 try { 31 strResult = String.valueOf(Double.parseDouble(strNumA) - Double.parseDouble(strNumB)); 32 } 33 catch (NumberFormatException ex){ 34 return "您输入的数据不正确,请检查!"; 35 } 36 catch (Exception ex) { 37 System.out.println(ex.getMessage()); 38 System.out.println("----------------------------------------"); 39 System.out.println(ex.getStackTrace()); 40 } 41 42 return strResult; 43 } 44 45 } 46 47 48 public class MultiplyOperator extends Operator{ 49 50 public String getResults() { 51 52 String strResult = ""; 53 54 try { 55 strResult = String.valueOf(Double.parseDouble(strNumA) * Double.parseDouble(strNumB)); 56 } 57 catch (NumberFormatException ex){ 58 return "您输入的数据不正确,请检查!"; 59 } 60 catch (Exception ex) { 61 System.out.println(ex.getMessage()); 62 System.out.println("----------------------------------------"); 63 System.out.println(ex.getStackTrace()); 64 } 65 66 return strResult; 67 } 68 } 69 70 71 public class ExceptOperator extends Operator{ 72 73 public String getResults() { 74 75 String strResult = ""; 76 77 try { 78 if ("0".equals(strNumB)) { 79 return "除数不能为0,请检查!"; 80 } 81 82 strResult = String.valueOf(Double.parseDouble(strNumA) / Double.parseDouble(strNumB)); 83 } 84 catch (NumberFormatException ex){ 85 return "您输入的数据不正确,请检查!"; 86 } 87 catch (Exception ex) { 88 System.out.println(ex.getMessage()); 89 System.out.println("----------------------------------------"); 90 System.out.println(ex.getStackTrace()); 91 } 92 93 return strResult; 94 } 95 }
3.最后再从多态的角度去继续完善这个计算器的功能,所谓的多态也就是编译时的类型与实际运行的类型不一致的场合,可以简单的理解为父类 变量名 = new 子类();
此时也就出现了多态,有了对多态的理解,就可以创建工厂类根据不同的运算符构造出不同的对象。通过多态,可以把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。对于后续计算器中要实现log,sin,tan等等的功能,就可以创建相应的子类以及在工厂类中再添加一个判断就可以了,当然这种添加判断就违背了开放-闭合的原则,因此出现了工厂方法模式,就避免了这种弊端。
工厂类的定义如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class OperatorFactory { 2 3 public static Operator getOperator(String Operator) { 4 5 if (StringConst.Plus.equals(Operator)) { 6 return new PlusOperator(); 7 }else if (StringConst.Minus.equals(Operator)) { 8 return new MinusOperator(); 9 }else if (StringConst.Multiply.equals(Operator)) { 10 return new MultiplyOperator(); 11 } 12 else if (StringConst.Except.equals(Operator)) { 13 return new ExceptOperator(); 14 } 15 else { 16 return null; 17 } 18 } 19 }
有了工厂类以后,就可以在主函数中根据用户的选择来通过工厂类创造出(new)不同的子类,利用多态的特性实现计算结果的功能。
修改后的主函数如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStreamReader; 4 5 6 public class Computer { 7 8 /** 9 * @param args 10 * @throws IOException 11 */ 12 public static void main(String[] args) throws IOException { 13 // TODO Auto-generated method stub 14 System.out.println("请输入数字1:"); 15 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 16 String strNumA = br.readLine(); 17 System.out.println("请输入运算符:"); 18 br = new BufferedReader(new InputStreamReader(System.in)); 19 String strOperator = br.readLine(); 20 System.out.println("请输入数字2:"); 21 br = new BufferedReader(new InputStreamReader(System.in)); 22 String strNumB = br.readLine(); 23 24 if (null == OperatorFactory.getOperator(strOperator)) { 25 System.out.println("您输入的运算符不正确,请检查!"); 26 return; 27 } 28 29 Operator operator = OperatorFactory.getOperator(strOperator); 30 operator.strNumA = strNumA; 31 operator.strNumB = strNumB; 32 System.out.println("运算结果为:"+operator.getResults()); 33 } 34 }
三、总结
至此,由一个面向过程设计的代码被修改成了面向对象设计的代码,主要是通过面向对象的三大特征:封装、继承、多态来改善了代码,简单工厂模式的宗旨也就是通过工厂类创造出(new)不同的对象,希望今后能够多运用“面向对象的思想”去思考程序,设计出优秀的程序。