1.业务需求
大家好,我是菠菜啊。在介绍这期工厂方法模式前,我们先来看看这样的需求:升级之前的计算器,增加对数和指数运算。(看这篇文章前可以先回顾《设计模式——工厂三兄弟之简单工厂》这篇)
2.初步实现
实现初步思路:
新增运算类的子类对数和指数运算类,修改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.优缺点以及应用场景
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程,延续了简单工厂创建者和使用者的分离的优点
- 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则
- 高层模块只需要知道产品的抽象类,解耦,满足迪米特法则
缺点:
- 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度
- 抽象产品只能生产一种产品
适用场景:
- 使用者只知道创建产品的工厂名,而不知道具体的产品名。
- 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
友情提示:请尊重作者劳动成果,如需转载本博客文章请注明出处!谢谢合作!
【作者:我爱吃菠菜 个人博客地址】