《大话设计模式》有感----简单工厂模式
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写它之后的设计模式的例子,对于我来说,写完这三个版本的计算器,我感觉思路都要清晰很多,谢谢《大话设计模式》!
以上是关于《大话设计模式》有感----简单工厂模式的主要内容,如果未能解决你的问题,请参考以下文章