作为一个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写它之后的设计模式的例子,对于我来说,写完这三个版本的计算器,我感觉思路都要清晰很多,谢谢《大话设计模式》!
原文:http://www.cnblogs.com/guyuexihong/p/7739431.html