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

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

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

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

原文地址:https://www.cnblogs.com/lanzhi/p/6469846.html