手撕设计模式——工厂三兄弟之工厂方法
1.业务需求
大家好,我是菠菜啊。在介绍这期工厂方法模式前,我们先来看看这样的需求:升级之前的计算器,增加对数和指数运算。(看这篇文章前可以先回顾《设计模式——工厂三兄弟之简单工厂》这篇)



2.初步实现
Talk is cheap,show me your code.
实现初步思路:
新增运算类的子类对数和指数运算类,修改OperationFactory类,增加创建对数和指数子类判断分支。

OperationFactory类:
public class OperationFactory {
public static AOpeartion createOperation(String operator){
AOpeartion opeartion=null;
switch (operator){
case "+":
opeartion=new OperationAdd();
break;
case "-":
opeartion=new OperationSub();
break;
case "*":
opeartion=new OperationMul();
break;
case "/":
opeartion=new OperationDiv();
break;
case "log":
opeartion=new OperationLog();
break;
case "pow":
opeartion=new OperationPow();
break;
}
return opeartion;
}
}
OperationLog类:
public class OperationLog extends AOpeartion {
@Override
public Double getOperationResult(double numbera, double numberb) {
return Math.log(numbera)/Math.log(numberb);
}
}
OperationPow类:
public class OperationPow extends AOpeartion {
@Override
public Double getOperationResult(double numbera, double numberb) {
return Math.pow(numbera,numberb);
}
}
思考:上述代码是按照上一篇简单工厂设计模式来设计的,每增加一种运算都要修改运算工厂类,影响了原有的代码运行,违反了开闭原则。期望新增这俩种运算不影响现有程序,并且有扩展性。那么问题出现在哪里呢?我们发现OperationFactory不够抽象,应该针对接口编程,而不是实现编程(《设计模式基础——设计原则介绍》这篇的依赖倒置原则)。
3.方案改进
改造思路:
新增抽象类AFactory,增加基础工厂类BasicOperationFactory、高级工厂类AdvanceOperationFactory子类,将之前的加减乘除运算子类对象的创建移动到BasicOperationFactory中,AdvanceOperationFactory中添加指数和对数运算子类对象的创建逻辑。增加OperationFactory2类,根据输入的运算符创建相应的工厂类,并且输出相应的运算子类。

AFactory类:
public abstract class AFactory {
public abstract AOpeartion createOperation(String operator);
}
BasicOperationFactory类:
public class BasicOperationFactory extends AFactory {
public AOpeartion createOperation(String operator){
AOpeartion opeartion=null;
switch (operator){
case "+":
opeartion=new OperationAdd();
break;
case "-":
opeartion=new OperationSub();
break;
case "*":
opeartion=new OperationMul();
break;
case "/":
opeartion=new OperationDiv();
break;
case "log":
opeartion=new OperationLog();
break;
case "pow":
opeartion=new OperationPow();
break;
}
return opeartion;
}
}
AdvanceOperationFactory类:
public class AdvanceOperationFactory extends AFactory {
public AOpeartion createOperation(String operator){
AOpeartion opeartion=null;
switch (operator){
case "log":
opeartion=new OperationLog();
break;
case "pow":
opeartion=new OperationPow();
break;
}
return opeartion;
}
}
OperationFactory2类:
public class OperationFactory2 {
public static AOpeartion createOperation(String operator){
AFactory factory=null;
switch (operator){
case "+":
case "-":
case "*":
case "/":
factory=new BasicOperationFactory();
break;
case "log":
case "pow":
factory=new AdvanceOperationFactory();
break;
}
return factory.createOperation(operator);
}
}
CalClient2类:
public class CalClient2 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入第一个数:");
double numbera=sc.nextDouble();
System.out.println("请输入运算符:");
String operator=sc.next();
System.out.println("请输入第二个数:");
double numberb=sc.nextDouble();
AOpeartion opeartion= OperationFactory2.createOperation(operator);
if(null!=opeartion){
System.out.println("运算结果为:"+(opeartion.getOperationResult(numbera,numberb)));
}else{
System.out.println("运算工厂获取运算类失败");
}
}
}
思考:OperationFactory工厂类通过输入的运算符去实例化相应合适的对象,通过多态返回父类的方式实现了计算器的结果。后续如果修改具体的计算方法只要修改具体的计算类即可,不会影响其它计算类。如果增加计算方法,增加实现相应的计算类的具体子类以及增加计算工厂类的switch分支即可。需求是变化的,而且我们不可能事先就了解所有的需求,所以我们在设计的时候就要考虑后续的可扩展性、可维护性。
4.定义和组成结构
工厂方法模式(FactoryMethod),定义一个创建产品对象的工厂接口,让工厂子类决定实例化那一个产品类。工厂方法使一个类的实例化延迟到其子类。
我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。
工厂方法模式的主要角色如下:
- 抽象工厂(AbstractFactory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 CreateProduct() 来创建产品。
- 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
- 抽象产品(AbstractProduct):定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

5.优缺点以及应用场景
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程,延续了简单工厂创建者和使用者的分离的优点
- 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则
- 高层模块只需要知道产品的抽象类,解耦,满足迪米特法则
缺点:
- 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度
- 抽象产品只能生产一种产品
适用场景:
-
使用者只知道创建产品的工厂名,而不知道具体的产品名。
-
创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
技术需要沉淀,同样生活也是~
个人链接:博客,欢迎一起交流











Just found this gem between classes! The secure RNG and local payments like GCash are huge for us here. Check out okfun ph app to start playing slots safely now.