• 设计模式——工厂模式在开发中的应用(简单计算器)


    下面以一个简单的计算器为例子来说明,怎么用工厂模式。

    如果你没有用任何设计模式,你可能会这样写:

    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

  • 相关阅读:
    使用边缘计算来改变5G世界中的网络
    解开关于人工智能的六个迷思
    哪些数据将成为区块链系统的关键数据?
    如何通过7个步骤构建机器学习模型
    人工智能的发展体现了人类社会由实向虚的趋势
    5G技术与人工智能的智能结合
    量子计算总是混合的,这需要不断协调
    7.5省队集训 tree
    bzoj2989&4170: 数列
    bzoj1010: [HNOI2008]玩具装箱toy
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6469846.html
Copyright © 2020-2023  润新知