下面以一个简单的计算器为例子来说明,怎么用工厂模式。
如果你没有用任何设计模式,你可能会这样写:
package com.meritit; import java.util.Scanner; public class MainClass { public static void main(String[] args) { double result = 0; //1.接收控制台输入 System.out.println("-----计算器程序-----"); System.out.println("输入第一个操作数"); Scanner scan = new Scanner(System.in); String strNum1 = scan.nextLine(); System.out.println("输入运算符"); String oper = scan.nextLine(); System.out.println("输入第二个操作数"); String strNum2 = scan.nextLine(); //2.进行运算 if("+".equals(oper)){ result = Double.parseDouble(strNum1) + Double.parseDouble(strNum2); }else if("-".equals(oper)){ result = Double.parseDouble(strNum1) - Double.parseDouble(strNum2); }else if("*".equals(oper)){ result = Double.parseDouble(strNum1) * Double.parseDouble(strNum2); }else if("/".equals(oper)){ result = Double.parseDouble(strNum1) / Double.parseDouble(strNum2); } //3.返回结果 System.out.println(strNum1 + oper + strNum2 + "=" + result); } }
这样写在判断运算符处代码重复率太高
我们可以这样写:
(1)一个抽象的计算类
package com.meritit; public abstract class Operation { private double num1; private double num2; 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 abstract double getResult(); }(2)具体的加法实现类
package com.meritit; public class AddOperation extends Operation{ @Override public double getResult() { double result = this.getNum1() + this.getNum2(); return result; } }
(3)主函数现在可以写成这样
package com.meritit; import java.util.Scanner; public class MainClass { public static void main(String[] args) { double result = 0; //1.接收控制台输入 System.out.println("-----计算器程序-----"); System.out.println("输入第一个操作数"); Scanner scan = new Scanner(System.in); String strNum1 = scan.nextLine(); System.out.println("输入运算符"); String oper = scan.nextLine(); System.out.println("输入第二个操作数"); String strNum2 = scan.nextLine(); double num1 = Double.parseDouble(strNum1); double num2 = Double.parseDouble(strNum2); //2.进行运算 if("+".equals(oper)){ Operation operation = new AddOperation(); operation.setNum1(num1); operation.setNum2(num2); result = operation.getResult(); }else if("-".equals(oper)){ result = Double.parseDouble(strNum1) - Double.parseDouble(strNum2); }else if("*".equals(oper)){ result = Double.parseDouble(strNum1) * Double.parseDouble(strNum2); }else if("/".equals(oper)){ result = Double.parseDouble(strNum1) / Double.parseDouble(strNum2); } //3.返回结果 System.out.println(strNum1 + oper + strNum2 + "=" + result); } }
但是上面的方法还是有问题,每次在运算的时候都要知道操作的类名,通过new对象来实例化。
现在我们来用简单工厂模式实现一下:
(1)创建OperationFactory工厂类(先写一个“+”运算)
package com.meritit; public class OperationFactory { public static Operation getOperation(String oper){ if("+".equals(oper)){ return new AddOperation(); }else{ return null; } } }(2)现在的主函数中可以这样写
package com.meritit; import java.util.Scanner; public class MainClass { public static void main(String[] args) { double result = 0; //1.接收控制台输入 System.out.println("-----计算器程序-----"); System.out.println("输入第一个操作数"); Scanner scan = new Scanner(System.in); String strNum1 = scan.nextLine(); System.out.println("输入运算符"); String oper = scan.nextLine(); System.out.println("输入第二个操作数"); String strNum2 = scan.nextLine(); double num1 = Double.parseDouble(strNum1); double num2 = Double.parseDouble(strNum2); //2.进行运算 Operation operation = OperationFactory.getOperation(oper); operation.setNum1(num1); operation.setNum2(num2); result = operation.getResult(); //3.返回结果 System.out.println(strNum1 + oper + strNum2 + "=" + result); } }
这样虽然可以扩展运算,但是还是要改工厂方法中的内容,外部是开放的,但内部不是封闭的。
我们现在用工厂方法模式来实现:
(1)将建立抽象工厂方法
package com.meritit; public interface OperationFactory { public Operation getOperation(); }
(2)Add(加法)工厂方法实现抽象工厂方法接口
package com.meritit; public class AddOperationFactory implements OperationFactory{ @Override public Operation getOperation() { return new AddOperation(); } }
(3)MainClass中这样写
package com.meritit; import java.util.Scanner; public class MainClass { public static void main(String[] args) { double result = 0; //1.接收控制台输入 System.out.println("-----计算器程序-----"); System.out.println("输入第一个操作数"); Scanner scan = new Scanner(System.in); String strNum1 = scan.nextLine(); System.out.println("输入运算符"); String oper = scan.nextLine(); System.out.println("输入第二个操作数"); String strNum2 = scan.nextLine(); double num1 = Double.parseDouble(strNum1); double num2 = Double.parseDouble(strNum2); //2.进行运算 if("+".equals(oper)){ OperationFactory oFactory = new AddOperationFactory(); Operation operation = oFactory.getOperation(); operation.setNum1(num1); operation.setNum2(num2); result = operation.getResult(); } //3.返回结果 System.out.println(strNum1 + oper + strNum2 + "=" + result); } }
这样写有个好处就是在增加运算(增加运算符号)时,不需要修改Operation和OperationFactory,只需要添加相应的
XxxOperation和XxxOperationFactory就行,但是这样写的话在MainClass中又要进行运算符判读。
现在我们使用反射技术封装一下:
(1)写一个配置文件operation.properties
+ = com.meritit.AddOperation
(2)写一个读取配置信息的工具类
package com.meritit; import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class ConfigUtil { public static String getConfig(String style){ Properties pro = new Properties(); InputStream inStream = ConfigUtil.class.getClassLoader().getResourceAsStream("operation.properties"); try { pro.load(inStream); } catch (IOException e) { e.printStackTrace(); } return pro.getProperty(style); } public static void main(String[] args) { System.out.println(getConfig("+")); } }
(3)AddOperationFactory中这样写
package com.meritit; public class AddOperationFactory implements OperationFactory{ @Override public Operation getOperation(String oper)throws Exception{ String type = ConfigUtil.getConfig(oper); return (Operation)Class.forName(type).newInstance(); } }
(4)MainClass不再需要判断运算符
package com.meritit; import java.util.Scanner; public class MainClass { public static void main(String[] args) { double result = 0; //1.接收控制台输入 System.out.println("-----计算器程序-----"); System.out.println("输入第一个操作数"); Scanner scan = new Scanner(System.in); String strNum1 = scan.nextLine(); System.out.println("输入运算符"); String oper = scan.nextLine(); System.out.println("输入第二个操作数"); String strNum2 = scan.nextLine(); double num1 = Double.parseDouble(strNum1); double num2 = Double.parseDouble(strNum2); //2.进行运算 try { OperationFactory oFactory = new AddOperationFactory(); Operation operation = oFactory.getOperation(oper); operation.setNum1(num1); operation.setNum2(num2); result = operation.getResult(); } catch (Exception e) { e.printStackTrace(); } //3.返回结果 System.out.println(strNum1 + oper + strNum2 + "=" + result); } }
这样就使用工厂方法模式完成了一个简单的计算器,如果有什么问题请指出。
源代码下载:http://download.csdn.net/detail/lxq_xsyu/5907383