第一章 简单工厂模式 (Simple Factory)
问题引入
如果说要通过代码写一个计算器,来代替加减乘除的笔算。那该怎么写呢?比如说可以写成这样:
public class Calculator {
public static void main(String[] args) {
double firstNumber = 0, secondNumber = 0;
String sign = null;
Scanner scanner = new Scanner(new BufferedInputStream(System.in));
System.out.print("请输入第一个数字:");
firstNumber = Double.valueOf(scanner.nextLine());
System.out.print("请输入运算符:(+-*/)");
sign = scanner.nextLine();
System.out.print("请输入第二个数字:");
secondNumber = Double.valueOf(scanner.nextLine());
if ("+".equals(sign)) {
System.out.println("计算结果为:" + (firstNumber + secondNumber));
} else if ("-".equals(sign)) {
System.out.println("计算结果为:" + (firstNumber - secondNumber));
} else if ("*".equals(sign)) {
System.out.println("计算结果为:" + (firstNumber * secondNumber));
} else if ("-".equals(sign)) {
System.out.println("计算结果为:" + (firstNumber / secondNumber));
} else {
System.out.println("不支持此运算");
}
}
}
暂时忽略掉参数校验,以及像是除数不能为空等这样的问题。这样就简单实现了计算器的功能,运行之后的结果,以加法为例:
请输入第一个数字:1
请输入运算符:(+-*/)+
请输入第二个数字:2
计算结果为:3.0ddddd
Process finished with exit code 0
目前计算器程序的问题:
- 提示语和运算的逻辑写到一块,耦合较高。
- 如果要添加新的运算,比如求平方,则需要修改Calculator类源码。可扩展性和可维护性较差。
问题解决
这样的程序可扩展性太差,耦合度较高,所以需要进行封装改造。代码如下:
将计算逻辑单独封装成一个类:
public class Operation {
/**
* 计算器运算方法
*
* @param number1 数字1
* @param number2 数字2
* @param operator 运算符
* @return 运算结果
*/
public double operation(double number1, double number2, String operator) {
double result = 0;
if ("+".equals(operator)) {
result = number1 + number2;
} else if ("-".equals(operator)) {
result = number1 - number2;
} else if ("*".equals(operator)) {
result = number1 * number2;
} else if ("-".equals(operator)) {
result = number1 / number2;
} else {
System.out.println("不支持此运算");
}
return result;
}
}
测试用例:
public class Calculator2Test {
public static void main(String[] args) {
double firstNumber = 0, secondNumber = 0;
String sign = null;
Scanner scanner = new Scanner(new BufferedInputStream(System.in));
System.out.print("请输入第一个数字:");
firstNumber = Double.valueOf(scanner.nextLine());
System.out.print("请输入运算符:(+-*/)");
sign = scanner.nextLine();
System.out.print("请输入第二个数字:");
secondNumber = Double.valueOf(scanner.nextLine());
Operation operation = new Operation();
double result = operation.operation(firstNumber, secondNumber, sign);
System.out.println("计算结果为:" + result);
}
}
这样就解决了,运算逻辑和提示语耦合的问题。下面解决下增加或者修改运算逻辑需要修改Operation类,会影响到其他运算的使用的问题。先说一下思路,抽象出一个运算接口,接口里定义一个运算的方法。然后建四个类去实现接口,分别是加减乘除类,然后重写其中的运算方法,实现自己的运算逻辑。这样的话,如果要添加新的运算,则只需要新建类去实现接口就好,并不会影响其他运算符的使用。代码如下:
运算接口:
public interface Operator {
/**
* 运算方法
*
* @param number1 数字1
* @param number2 数字2
* @return
*/
double compute(double number1, double number2);
}
加减乘除类:
public class Addition implements Operator {
public double compute(double number1, double number2) {
return number1 + number2;
}
}
public class Subtraction implements Operator {
public double compute(double number1, double number2) {
return number1 - number2;
}
}
public class Multiplication implements Operator {
public double compute(double number1, double number2) {
return number1 * number2;
}
}
public class Division implements Operator {
public double compute(double number1, double number2) {
if (number2 == 0) {
System.out.println("除数不能为0");
}
return number1 / number2;
}
}
运算符工厂类:
public class OperatorFactory {
public Operator getOperator(String operator) {
if ("+".equals(operator)) {
return new Addition();
} else if ("-".equals(operator)) {
return new Subtraction();
} else if ("*".equals(operator)) {
return new Multiplication();
} else if ("/".equals(operator)) {
return new Division();
} else {
System.out.println("不支持此运算");
return null;
}
}
}
这样就实现了封装和解耦,每个运算符之间互不影响,各自实现自己的运算逻辑。如果想添加一种新的运算逻辑,则只需要新建一个类去实现Operator接口,然后实现其中的运算方法,然后再工厂类的if判断加一个新的分支就好了。比之前的写法耦合度降低了,可扩展性提高了,也变得易于维护了。测试一下:
public class Calculator3Test {
public static void main(String[] args) {
OperatorFactory operatorFactory = new OperatorFactory();
double firstNumber = 0, secondNumber = 0;
String sign = null;
Scanner scanner = new Scanner(new BufferedInputStream(System.in));
System.out.print("请输入第一个数字:");
firstNumber = Double.valueOf(scanner.nextLine());
System.out.print("请输入运算符:(+-*/)");
Operator operator = operatorFactory.getOperator(scanner.nextLine());
System.out.print("请输入第二个数字:");
secondNumber = Double.valueOf(scanner.nextLine());
System.out.println("运算结果为:" + operator.compute(firstNumber, secondNumber));
}
}
运行结果为:
请输入第一个数字:1
请输入运算符:(+-*/)/
请输入第二个数字:2
运算结果为:0.5
Process finished with exit code 0
如果想添加一个取余数的算法,则需要新建一个类去实现Operator接口,然后在工厂中添加一个if分支:
public class Remainder implements Operator {
public double compute(double number1, double number2) {
return number1 % number2;
}
}
工厂类修改:
public Operator getOperator(String operator) {
if ("+".equals(operator)) {
return new Addition();
} else if ("-".equals(operator)) {
return new Subtraction();
} else if ("*".equals(operator)) {
return new Multiplication();
} else if ("/".equals(operator)) {
return new Division();
} else if ("%".equals(operator)) {
return new Remainder();
} else {
System.out.println("不支持此运算");
return null;
}
}
重新运行测试类:
请输入第一个数字:10
请输入运算符:(+-*/%)%
请输入第二个数字:3
运算结果为:1.0
Process finished with exit code 0
小结
简单工厂模式适用于解决对象的创建问题。