《大话设计模式》有感----简单工厂模式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《大话设计模式》有感----简单工厂模式相关的知识,希望对你有一定的参考价值。

作为一个Java初学者,看《大话设计模式》的时候,看到第一个例子,感同身受啊。

所以今天,我用Java语言编写这个程序,从面向过程-->面向对象-->简单工厂模式的转变过程。

需求:请用C++、Java、C#或VB.NET任意一种面向对象语言实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果。

这是面向过程的解决思路:

import java.math.BigDecimal;
import java.util.Scanner;
import java.util.regex.Pattern;

/**
 * 面向过程的计算器
 * 
 * Version 0.1
 *
 * @author 孤月汐鸿
 *
 */
public class Calculator0_1 {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		// 输入第一个数
		System.out.println("请输入第一个数字:");
		String firstNumber = scan.next();
		while (!isNumber(firstNumber)) {
			System.out.println("请输入第一个数字:");
			firstNumber = scan.next();
		}

		// 输入一个操作符(+ - * /)
		System.out.println("请输入运算符(目前只支持+、-、*、/)");
		String operator = scan.next();
		while (!isValidOperator(operator)) {
			System.out.println("暂时还没有这种运算符。。。。");
			System.out.println("请输入运算符(目前只支持+、-、*、/)");
			operator = scan.next();
		}
		// 输入第二个数
		System.out.println("请输入第二个数字:");
		String secondNumber = scan.next();
		while (!isNumber(secondNumber)) {
			System.out.println("请输入第二个数字:");
			secondNumber = scan.next();
		}
		scan.close();
		
		//为了解决double运算的精度问题,使用Java自带的java.math包下的BigDecimal类的方法进行运算。
		switch (operator) {
		case "+":
			System.out.println(new BigDecimal(firstNumber).add(new BigDecimal(secondNumber)).doubleValue());
			break;
		case "-":
			System.out.println(new BigDecimal(firstNumber).subtract(new BigDecimal(secondNumber)).doubleValue());
			break;
		case "*":
			System.out.println(new BigDecimal(firstNumber).multiply(new BigDecimal(secondNumber)).doubleValue());
			break;
		case "/":
			System.out.println(new BigDecimal(firstNumber).divide(new BigDecimal(secondNumber),10,BigDecimal.ROUND_HALF_UP).doubleValue());
			break;
		default:
			System.out.println("暂时还没有这种运算符。。。。");
			break;
		}
	}

	/**
	 * 判断是否是数字(正负整数、正负浮点数)
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isNumber(String str) {
		Pattern pa = Pattern.compile("^([-|+]?\\d+)(\\.\\d+)?$");
		return pa.matcher(str).matches();
	}
	
	/**
	 * 判断是否为指定的运算符
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isValidOperator(String str) {
		Pattern pa = Pattern.compile("[-|+|*|/]");
		return pa.matcher(str).matches();
	} 
}

  代码可能还有些bug,请谅解。

  大部分的初学者在学习面向对象编程的时候,思想可能都还没有转变过来,还在用面向过程的思想解决问题。

  接下来是我的计算器第二版-----------面向对象编程。

  第一个是操作方法接口(Operateable),每一种运算符都有一个运算方法,所以写成一个运算接口,每一种运算符来实现各自的运算方法。

/**
 * 运算接口
 * 
 * @author 孤月汐鸿
 *
 */
public interface Operateable {

	double operate(String firstNumber, String secondNumber);

}

  第二个要写的就是当前的四种运算符的各个运算方法

    1、加法类(AddOperator.java)

import java.math.BigDecimal;

/**
 * 加法运算 为了解决double和float运算精度的问题,使用java.math包下的BigDecimal方法运算
 * 
 * @author 孤月汐鸿
 *
 */
public class AddOperator implements Operateable {

	@Override
	public double operate(String firstNumber, String secondNumber) {
		return new BigDecimal(firstNumber).add(new BigDecimal(secondNumber)).doubleValue();
	}

}

    2、减法类(SubOperator.java)

import java.math.BigDecimal;

/**
 * 减法运算 为了解决double和float运算精度的问题,使用java.math包下的BigDecimal方法运算
 * 
 * @author 孤月汐鸿
 *
 */
public class SubOperator implements Operateable {

	@Override
	public double operate(String firstNumber, String secondNumber) {
		return new BigDecimal(firstNumber).subtract(new BigDecimal(secondNumber)).doubleValue();
	}

}

    3、乘法类(MulOperator.java)

import java.math.BigDecimal;

/**
 * 乘法运算 为了解决double和float运算精度的问题,使用java.math包下的BigDecimal方法运算
 * 
 * @author 孤月汐鸿
 *
 */
public class MulOperator implements Operateable {

	@Override
	public double operate(String firstNumber, String secondNumber) {
		return new BigDecimal(firstNumber).multiply(new BigDecimal(secondNumber)).doubleValue();
	}

}

    4、除法类(DivOperator.java)

import java.math.BigDecimal;

/**
 * 除法运算 为了解决double和float运算精度的问题,使用java.math包下的BigDecimal方法运算
 * 
 * @author 孤月汐鸿
 *
 */
public class DivOperator implements Operateable {

	@Override
	public double operate(String firstNumber, String secondNumber) {
		return new BigDecimal(firstNumber).divide(new BigDecimal(secondNumber), 10, BigDecimal.ROUND_HALF_UP)
				.doubleValue();
	}
}

    最后写一个程序的主入口,计算器类(Calculator0_2.java)

import java.util.Scanner;
import java.util.regex.Pattern;

/**
 * 面向对象编程计算器
 * 
 * Version 0.2
 *
 * @author 孤月汐鸿
 *
 */

public class Calculator0_2 {

	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		// 输入第一个数
		System.out.println("请输入第一个数字:");
		String firstNumber = scan.next();
		while (!isNumber(firstNumber)) {
			System.out.println("请输入第一个数字:");
			firstNumber = scan.next();
		}

		// 输入一个操作符(+ - * /)
		System.out.println("请输入运算符(目前只支持+、-、*、/)");
		String op = scan.next();
		while (!isValidOperator(op)) {
			System.out.println("暂时还没有这种运算符。。。。");
			System.out.println("请输入运算符(目前只支持+、-、*、/)");
			op = scan.next();
		}
		// 输入第二个数
		System.out.println("请输入第二个数字:");
		String secondNumber = scan.next();
		while (!isNumber(secondNumber)) {
			System.out.println("请输入第二个数字:");
			secondNumber = scan.next();
		}
		scan.close();
		Operateable operator = null;
		switch (op) {
		case "+":
			operator = new AddOperator();
			break;
		case "-":
			operator = new SubOperator();
			break;
		case "*":
			operator = new MulOperator();
			break;
		case "/":
			operator = new DivOperator();
			break;
		default:
			System.out.println("暂时还没有这种运算符。。。。");
			break;
		}
		System.out.println(operator.operate(firstNumber, secondNumber));
	}
	/**
	 * 判断是否是数字(正负整数、正负浮点数)
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isNumber(String str) {
		Pattern pa = Pattern.compile("^([-|+]?\\d+)(\\.\\d+)?$");
		return pa.matcher(str).matches();
	}
	
	/**
	 * 判断是否为指定的运算符
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isValidOperator(String str) {
		Pattern pa = Pattern.compile("[-|+|*|/]");
		return pa.matcher(str).matches();
	} 
}

  当我写完这面向对象的计算器第二版时,感觉也是一片大好,但看了《大话设计模式》中的大鸟的话,这还是不行,计算器类就应该只有输入操作,和结果显示就行了,如果我还要添加操作符的话,还得修改这个类的switch语句,对于扩展很不利,不可能客户需要添加需求还要改客户手上的客户端代码,所以引入了简单工厂模式,将所有的功能类代码都放在了后台,计算器类只留下了输入和结果显示的功能,以后添加操作符也不用修改它了。

  接下来是我的计算器第三版---------简单工厂模式

    1、第一个类依然是运算符接口(Operateable.java)

/**
 * 运算接口
 * 
 * @author 孤月汐鸿
 *
 */
public interface Operateable {

	double operate(String firstNumber, String secondNumber);

}

    2、几个运算符类

      2.1、加法类(AddOperator.java)

import java.math.BigDecimal;

/**
 * 加法运算 为了解决double和float运算精度的问题,使用java.math包下的BigDecimal方法运算
 * 
 * @author 孤月汐鸿
 *
 */
public class AddOperator implements Operateable {

	@Override
	public double operate(String firstNumber, String secondNumber) {
		return new BigDecimal(firstNumber).add(new BigDecimal(secondNumber)).doubleValue();
	}

}

      2.2、减法类(SubOperator.java)

import java.math.BigDecimal;

/**
 * 减法运算 为了解决double和float运算精度的问题,使用java.math包下的BigDecimal方法运算
 * 
 * @author 孤月汐鸿
 *
 */
public class SubOperator implements Operateable {

	@Override
	public double operate(String firstNumber, String secondNumber) {
		return new BigDecimal(firstNumber).subtract(new BigDecimal(secondNumber)).doubleValue();
	}

}

      2.3、乘法类(MulOperator.java)

import java.math.BigDecimal;

/**
 * 乘法运算 为了解决double和float运算精度的问题,使用java.math包下的BigDecimal方法运算
 * 
 * @author 孤月汐鸿
 *
 */
public class MulOperator implements Operateable {

	@Override
	public double operate(String firstNumber, String secondNumber) {
		return new BigDecimal(firstNumber).multiply(new BigDecimal(secondNumber)).doubleValue();
	}

}

      2.4、除法类(DivOperator.java)

import java.math.BigDecimal;

/**
 * 除法运算 为了解决double和float运算精度的问题,使用java.math包下的BigDecimal方法运算
 * 
 * @author 孤月汐鸿
 *
 */
public class DivOperator implements Operateable {

	@Override
	public double operate(String firstNumber, String secondNumber) {
		return new BigDecimal(firstNumber).divide(new BigDecimal(secondNumber), 10, BigDecimal.ROUND_HALF_UP)
				.doubleValue();
	}
}

 

    3、我写了一个操作工厂类(OperatorFactory),将计算器类中的运算符判断放入了这里。

/**
 * 运算类工厂
 * 
 * @author 孤月汐鸿
 *
 */
public class OperatorFactory {

        //定义一个运算符接口对象,利用Java语言多态的特性
	private static Operateable operator;

        /**
         * 生成指定的运算符类
         * 
         */
	public static Operateable createOperator(String op) {
		switch (op) {
		case "+":
			operator = new AddOperator();
			break;
		case "-":
			operator = new SubOperator();
			break;
		case "*":
			operator = new MulOperator();
			break;
		case "/":
			operator = new DivOperator();
			break;
		default:
			System.out.println("暂时还没有这种运算符。。。。");
			break;
		}
		return operator;
	}
}

    4、为了方便我还写了一个输入字符串判断类(IsRequirements.java),基本上涵盖了常用的字符串判断

import java.util.regex.Pattern;

/**
 * 输入字符串判断
 * 
 * @author 孤月汐鸿
 *
 */
public class IsRequirements {

	private IsRequirements() {
	}

	private static IsRequirements ir = new IsRequirements();

	public static IsRequirements getInstance() {
		return ir;
	}

	/**
	 * 判断是否是数字(正负整数、正负浮点数)
	 * 
	 * @param str
	 * @return
	 */
	public boolean isNumber(String str) {
		Pattern pa = Pattern.compile("^([-|+]?\\d+)(\\.\\d+)?$");
		return pa.matcher(str).matches();
	}

	/**
	 * 判断是否为指定的运算符
	 * 
	 * @param str
	 * @return
	 */
	public boolean isValidOperator(String str) {
		Pattern pa = Pattern.compile("[-|+|*|/]");
		return pa.matcher(str).matches();
	}

	/**
	 * 判断是否为正整数
	 * 
	 * @param str
	 * @return
	 */
	public boolean isPositiveInteger(String str) {
		Pattern pa = Pattern.compile("^[1-9]\\d*$");
		return pa.matcher(str).matches();
	}

	/**
	 * 判断是否为汉字
	 * 
	 * @param str
	 * @return
	 */
	public boolean isHanZi(String str) {
		Pattern pa = Pattern.compile("^[\\u4e00-\\u9fa5]{0,}$");
		return pa.matcher(str).matches();
	}

	/**
	 * 判断是否为Email地址
	 * 
	 * @param str
	 * @return
	 */
	public boolean isEmailAddress(String str) {
		Pattern pa = Pattern.compile("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$");
		return pa.matcher(str).matches();
	}

	/**
	 * 判断是否为域名
	 * 
	 * @param str
	 * @return
	 */
	public boolean isDomainName(String str) {
		Pattern pa = Pattern.compile("[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.? ");
		return pa.matcher(str).matches();
	}
}

    5、最后就是计算器类了,现在的计算器基本上已经可以很方便的扩展了

import java.util.Scanner;

/**
 * 面向对象编程 计算器
 * 
 * Version 0.3
 *
 * @author 孤月汐鸿
 *
 */
public class Calculator0_3 {

	public static void main(String[] args) {

		Scanner scan = new Scanner(System.in);
		IsRequirements ir = IsRequirements.getInstance();
		// 输入第一个数
		System.out.println("请输入第一个数字:");
		String firstNumber = scan.next();
		while (!ir.isNumber(firstNumber)) {
			System.out.println("请输入第一个数字:");
			firstNumber = scan.next();
		}
		// 输入一个操作符(+ - * /)
		System.out.println("请输入运算符(目前只支持+、-、*、/)");
		String op = scan.next();
		while (!ir.isValidOperator(op)) {
			System.out.println("暂时还没有这种运算符。。。。");
			System.out.println("请输入运算符(目前只支持+、-、*、/)");
			op = scan.next();
		}
		// 输入第二个数
		System.out.println("请输入第二个数字:");
		String secondNumber = scan.next();
		while (!ir.isNumber(secondNumber)) {
			System.out.println("请输入第二个数字:");
			secondNumber = scan.next();
		}
		scan.close();
		System.out.println("运算结果:" + OperationFactory.createOperator(op).operate(firstNumber, secondNumber));
	}

}

  写到这里,这篇文章也差不多了,计算器第三版已经基本上符合了程序的易扩展性、功能与客户端分离,可以很方便的使用了。如果还需要继续添加需求,就只需要修改输入字符判断类(IsRequirements.java)里面的指定字符判断条件和运算符工厂,将新增的预算类加入到工厂类中就行了,根本不需要修改其他代码。

  《大话设计模式》真的很不错,之后我还会继续用Java写它之后的设计模式的例子,对于我来说,写完这三个版本的计算器,我感觉思路都要清晰很多,谢谢《大话设计模式》!

 

以上是关于《大话设计模式》有感----简单工厂模式的主要内容,如果未能解决你的问题,请参考以下文章

大话设计模式——策略模式

[大话设计模式]学习笔记——简单工厂模式

《大话设计模式》——读后感 代码无错就是优?——简单工厂模式

大话设计模式--第一章 简单工厂设计模式

java 之 工厂模式(大话设计模式)

《大话设计模式》之简单工厂模式