简单工厂模式
本篇简单工厂模式,借鉴参考《大话设计模式》中的例子,使用了 Java 来进行简单的实现。
使用面向对象语言实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果
mermaid的类图在手机上显示不友好,推荐使用电脑进行阅读。也可以克隆项目到本地,在 idea 中安装mermaid插件进行阅读。项目地址:design-patterns ,将会持续更新各种模式的应用,以及后续的实际案例应用。
普通实现
public class Calculator {
public static void main(String[] args) {
/*
实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果
*/
Scanner scanner = new Scanner(System.in);
System.out.print("请输入数字 A:");
String numberA = scanner.nextLine();
System.out.print("请输入运算符号(+、-、*、/):");
String operator = scanner.nextLine();
System.out.print("请输入数字 B:");
String numberB = scanner.nextLine();
String result = "";
switch (operator) {
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 ("0".equals(numberB)) {
System.out.println("除数不能为 0");
return;
}
result = String.valueOf(Double.parseDouble(numberA) / Double.parseDouble(numberB));
break;
default:
System.out.println("运算符输入错误");
}
System.out.printf("计算结果:%s %s %s = %s %n", numberA, operator, numberB, result);
}
}
以上是一个简单的计算机程序实现,在控制台输入两个数和运算符之后,得到计算结果,这种实现方式只能满足当前的需求,如果有新的需求,要求提供开平方等其他运算,就需要修改源代码了,可扩展性比较差,若之后需求逐渐增多,此处代码会更加难以维护。
改造简单工厂模式
改造思路
将计算器代码中,负责运算的部分抽离成一个类,然后将具体的运算分别放到运算类的子类中,这样无论是扩展多少运算方式,都只需要继承运算类,并重写运算方法即可,这样做的好处是对于之前的业务逻辑的影响几乎为 0,不用担心新增功能之后,之前的业务逻辑无法使用。
运算类
public 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 Double getResult() throws Exception {
return 0.0;
}
}
我们在运算类中,定义了参与运算的两个属性
NumberA和NumberB,还有一个getResult()方法,这个方法用来给子类重写的。
加减乘除类
// 加法
public class Addition extends Operation {
@Override
public Double getResult() {
return getNumberA() + getNumberB();
}
}
// 减法
public class Subtraction extends Operation {
@Override
public Double getResult() {
return getNumberA() - getNumberB();
}
}
// 乘法
public class Multiplication extends Operation {
@Override
public Double getResult() {
return getNumberA() * getNumberB();
}
}
// 除法
public class Division extends Operation {
@Override
public Double getResult() throws Exception {
if (getNumberB() == 0) {
throw new Exception("除数不能为 0");
}
return getNumberA() / getNumberB();
}
}
以上加减乘除法的类,分别继承了运算类,并重写了父类的
getResult()方法,实现自己每个类中的业务逻辑,若想新增其他运算方法,只需要新增运算方法类,并继承运算类,重写父类的getResult()方法即可。(当然,还需要修改简单工厂类,添加创建实例的逻辑。)
简单运算工厂类
public class OperationFactory {
public static Operation createOperator(String operator) throws Exception {
Operation operation;
switch (operator) {
case "+":
operation = new Addition();
break;
case "-":
operation = new Subtraction();
break;
case "*":
operation = new Multiplication();
break;
case "/":
operation = new Division();
break;
default:
throw new Exception("运算符输入错误");
}
return operation;
}
}
简单工厂类,定义了一个
createOprator(String operator)方法,用来根据用户输入的运算符不同,创建对应的实例。
测试类
public class Calculator {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入数字 A:");
String numberA = scanner.nextLine();
System.out.print("请输入运算符号(+、-、*、/):");
String operator = scanner.nextLine();
System.out.print("请输入数字 B:");
String numberB = scanner.nextLine();
Operation operation;
operation = OperationFactory.createOperator(operator);
operation.setNumberA(Double.valueOf(numberA));
operation.setNumberB(Double.valueOf(numberB));
Double result = operation.getResult();
System.out.printf("计算结果:%s %s %s = %s %n", numberA, operator, numberB, result);
}
}
对比不使用设计模式的实现,不需要知道内部是怎么运算的,只需要把需要计算的数字和运算符号传给简单工厂类,就可以获得运算结果。这样可以使模块之间的依赖关系更加松散。
结构图
---
title: 计算器程序结构图
---
classDiagram
direction lr
Operation <|-- Addition
Operation <|-- Subtraction
Operation <|-- Multiplication
Operation <|-- Division
Operation <.. OperationFactory
class OperationFactory {
+ createOperation() Operation
}
class Operation {
+ double NumberA
+ double NumberB
+ GetResult() double
}
class Addition {
+ GetResult() double
}
class Subtraction {
+ GetResult() double
}
class Multiplication {
+ GetResult() double
}
class Division {
+ GetResult() double
}
优缺点
优点
-
易于理解和实现:简单工厂模式的名称本身就揭示了它的工作方式,这使得初学者易于理解。此外,该模式相对简单,易于实现和维护。
-
提高代码的可重用性:简单工厂模式允许将一组相关或相互依赖的对象创建出来,这使得代码可以更易于维护和扩展。
-
支持模块间的松耦合:通过使用工厂模式,可以将模块之间的耦合度降低。客户端不直接创建对象,而是由工厂创建,这使得模块之间的依赖关系更加松散。
缺点
-
工厂方法模式可能会导致大量对象创建:当工厂方法模式的一组对象之间有紧密的依赖关系时,可能会导致创建大量对象,这可能会浪费内存和时间。
-
可能会增加代码的复杂度:虽然简单工厂模式易于理解和实现,但它的实现可能会增加代码的复杂度。特别是在需要创建大量相关或相互依赖的对象时,这可能会使代码变得难以理解和调试。
-
可能降低代码的可测试性:由于简单工厂模式需要创建一个抽象工厂类和多个具体工厂类,这可能会降低代码的可测试性。如果需要测试这些工厂类,则需要创建独立的测试用例,这可能会增加代码的复杂性。
适用场景
-
创建复杂对象:如果一个对象的创建过程比较复杂,包含多个步骤或依赖于其他对象,可以使用简单工厂模式将创建过程封装起来,简化客户端的代码。
-
隐藏对象创建细节:如果客户端需要创建多个不同的对象,可以使用简单工厂模式将对象创建的细节封装起来,使客户端无需关心对象创建的具体实现。
-
代码解耦:使用简单工厂模式可以将客户端代码与产品类的代码解耦,使得客户端代码更加灵活,可以轻松地切换不同的产品实现。
-
限制对象的创建:使用简单工厂模式可以限制对象的创建,确保只有工厂能够创建对象,避免客户端直接创建对象导致的错误。
-
提高代码复用性:如果多个对象的创建过程相似,可以使用简单工厂模式将创建过程封装起来,提高代码复用性。