目录
一、前言
二、简单工厂模式
1、计算器例子
2、优化后版本
3、结合面向对象进行优化(封装)
3.1、Operation运算类
3.2、客户端
4、利用面向对象三大特性(继承和多态)
4.1、Operation类
4.2、加法类
4.3、减法类
4.4、乘法类
4.5、除法类
4.6、简单工厂
4.7、客户端
5、简单工厂模式优点
6、简单工厂模式缺点
三、总结
一、前言
简单工厂模式不属于GoF23种设计模式之一,但是实际中用途广泛,并且可以作为学习“工厂方法模式”以及“抽象工厂模式”的基础。在简单工厂模式中,工厂类提供一个创建产品的工厂方法,用于创建各种产品。客户端只需传入对应的参数,利用该方法即可根据传入参数的不同返回不同的具体产品对象。
二、简单工厂模式
简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
因为在简单工厂模式用于创建实例的方法是静态的方法,因此简单工厂模式又被称为静态工厂方法模式,它属于类创建型模式。
在介绍简单工厂之前先来看一个简单的计算器小栗子。
1、计算器例子
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数字A:");
String A = scanner.nextLine();
System.out.println("请选择运算符号(+、-、*、/):");
String B = scanner.nextLine();
System.out.println("请输入数字B:");
String C = scanner.nextLine();
String D = "";
if(B == "+"){
D = String.valueOf(Double.parseDouble(A) + Double.parseDouble(C));
}
if(B == "-"){
D = String.valueOf(Double.parseDouble(A) - Double.parseDouble(C));
}
if(B == "*"){
D = String.valueOf(Double.parseDouble(A) * Double.parseDouble(C));
}
if(B == "/"){
D = String.valueOf(Double.parseDouble(A) / Double.parseDouble(C));
}
System.out.println("运算结果:"+D);
}
这段代码存在的问题:
- 这样命名是非常不规范的。像A、B、C、D这些,别人扎眼一看肯定不知道这是在做什么。
- 判断分支,这样的写法,意味着每个条件都要做判断,等于计算机做了三次无用功。
- 如果除数时,客户输入了0怎么办,如果用户输入的是字符符号而不是数字怎么办。
2、优化后版本
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数字A:");
String numberA = scanner.nextLine();
System.out.println("请选择运算符号(+、-、*、/):");
String operate = scanner.nextLine();
System.out.println("请输入数字B:");
String numberB = scanner.nextLine();
String result = "";
switch (operate ){
case "+":
result = String.valueOf(Double.parseDouble(numberA) + Double.parseDouble(numberB));
break;
case "-":
result = String.valueOf(Double.parseDouble(numberA) - Double.parseDouble(numberB));
break;
case "*":
result = String.valueOf(Double.parseDouble(numberA) * Double.parseDouble(numberB));
break;
case"/":
if (numberB != "0"){
result = String.valueOf(Double.parseDouble(numberA) / Double.parseDouble(numberB));
}else{
result = "除数不能为0";
}
break;
}
System.out.println("运算结果:"+result);
}catch (Exception e){
System.out.println(e);
}
}
可以看到这一版中优化了变量的命名,将if判断更换成了switch case语句,增加了除数判断是否为0。
3、结合面向对象进行优化(封装)
3.1、Operation运算类
public class Operation {
public static String getResult(double numberA, double numberB, String operate){
String result = "";
switch (operate){
case "+":
result = String.valueOf(numberA+ numberB);
break;
case "-":
result = String.valueOf(numberA -numberB);
break;
case "*":
result = String.valueOf(numberA * numberB);
break;
case"/":
if (numberB != 0){
result = String.valueOf(numberA / numberB);
}else{
result = "除数不能为0";
}
break;
}
return result;
}
}
3.2、客户端
public class Program {
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数字A:");
String numberA = scanner.nextLine();
System.out.println("请选择运算符号(+、-、*、/):");
String operate = scanner.nextLine();
System.out.println("请输入数字B:");
String numberB = scanner.nextLine();
String result = "";
Operation.getResult(Double.parseDouble(numberA), Double.parseDouble(numberB),operate);
System.out.println("运算结果:"+result);
}catch (Exception e){
System.out.println(e);
}
}
}
4、利用面向对象三大特性(继承和多态)
4.1、Operation类
public abstract class Operation {
private double numberA;
private double numberB;
public double getNumberA() {
return numberA;
}
public void setNumberA(double numberA) {
this.numberA = numberA;
}
public double getNumberB() {
return numberB;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
public abstract double getResult() throws Exception;
}
4.2、加法类
public class OperationAdd extends Operation{
@Override
public double getResult() {
return getNumberA()+getNumberB();
}
}
4.3、减法类
public class OperationSub extends Operation{
@Override
public double getResult() {
return getNumberB() - getNumberB();
}
}
4.4、乘法类
public class OperationMul extends Operation{
@Override
public double getResult() {
return getNumberA() * getNumberB();
}
}
4.5、除法类
public class OperationDiv extends Operation{
@Override
public double getResult() throws Exception {
if (getNumberB() != 0){
return getNumberA() / getNumberB();
}
throw new Exception("除数不能为0");
}
}
4.6、简单工厂
public class OperationFactory {
public static Operation createOperate(String operate){
Operation operation = null;
switch (operate){
case "+":
operation = new OperationAdd();
break;
case "-":
operation = new OperationSub();
break;
case "*":
operation = new OperationMul();
break;
case"/":
operation = new OperationDiv();
break;
}
return operation;
}
}
4.7、客户端
public class Program {
public static void main(String[] args) throws Exception {
Operation operation;
operation = OperationFactory.createOperate("+");
operation.setNumberA(2);
operation.setNumberB(4);
double result = operation.getResult();
System.out.println(result);
}
}
5、简单工厂模式优点
1、工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
2、客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
3、通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
6、简单工厂模式缺点
1、由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
2、使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
3、系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
4、简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
三、总结
使用了简单工厂之后,如果有一天我们需要更改假发运算,只需要更改OperationAdd就可以了,如果需要增加各种复杂运算,例如:平方根、自然对数、正弦等,需要增加相应的运算子类,修改运算类工厂,在switch中增加分支,来看一下简单工厂的类结构。