工厂模式属于创建型设计模式的一种,其实在我看来它更是在面向对象编程语言的抽象层的更加灵活的应用。工厂模式其实在创建型模式中难度较高,整体的理解上需要一定时间进行消化,在一些Java常见框架中,这种模式也是频繁出现的设计,如果我们可以在自己的项目中灵活使用这个模式那将会让我们的代码更加灵活、耦合度会更低。此篇文章我们将工厂模式拆成三个不同的工厂形式来循序渐进地讲解,以便开发者能够深刻理解工厂设计模式。
1. 概念
工厂模式(Factory Pattern)提供了一种创建对象的最佳方式。我们不必关心对象的创建细节,只需要根据不同情况获取不同产品即可。
2. 简单工厂(Simple Factory)
2.1 简介
简单工厂其实从类图上我们就能看出来,其实我们就是有一个抽象的产品,类似于一个产品族一样,在我的例子中这个抽象产品就是一个Car,那么我们可以拥有两种不同种类的Car,比如VanCar以及MiniCar,这个就是我的两个具体产品。
那么我们在外部想用这个产品的时候,我们可以通过直接new出实例的方式创建对象,但是既然是一个产品族(都是抽象Car的实现),我们完全可以定义一个Factory类专门来为这个Car产品族创建相应类型的实例,外部系统调用的过程中直接通过一个Facotry对象,只需要告诉我们需要什么类型的Car即可为我们创建出来相应的对象。
2.2 代码实现
Factory类:
public class WuLinSimpleFactory {/**** @param type Class: 好像具有扩展性,但是没有解决实际问题* @return*/public AbstractCar newCar(String type){//核心方法:一切从简if("van".equals(type)){// 钣金、喷漆、放发动机、申请环保return new VanCar();}else if("mini".equals(type)){return new MiniCar();}//.....//更多的产品,违反开闭原则。应该直接扩展出一个类来造return null;}
}
外部系统调用:
public class MainTest {public static void main(String[] args) {WuLinSimpleFactory factory = new WuLinSimpleFactory();AbstractCar van = factory.newCar("van");AbstractCar mini = factory.newCar("mini");AbstractCar zz = factory.newCar("zz");van.run();mini.run();}
}
2.3 总结
经验丰富的开发者可能发现了,这样的设计严重违反了我们的开闭原则,原因是我们创建什么类型的Car都写死在工厂里,如果我们这是有新的种类的Car,比如说RaceCar,那么我们需要为此修改Factory中的代码;同时如何产品过多,我们可能会需要在Factory中嵌入更多的if-else代码块,导致代码可读性极差。
简单工厂模式仅仅适用于产品极少的情况下或者在此系统中不会拥有新的产品出现(这种情况几乎无法保证,因为谁也没有把握说未来此系统到底会迭代成什么样子)。
3. 工厂方法(Factory Method)
3.1 简介
当我们分析出来上一篇提到的简单工厂的一些弊端后,我们可以进一步升级我们的工厂模式,聪明的架构师想到了:我们可以把工厂进行抽象,每一种产品都对应着一个工厂(此工厂需要继承抽象工厂),那么这样我们就可以保证系统中的开闭原则。是的,这种实现形式就是我们所要讲的工厂方法。
3.2 代码实现
抽象工厂:
/*** 抽象工厂的层级*/
public abstract class AbstractCarFactory {public abstract AbstractCar newCar();
}
MiniCar工厂:
public class MiniCar extends AbstractCar {public MiniCar(){this.engine = "四缸水平对置发动机";}@Overridepublic void run() {System.out.println(engine+"--> 嘟嘟嘟...");}
}
VanCar工厂:
public class WulinVanCarFactory extends AbstractCarFactory {@Overridepublic AbstractCar newCar() {return new VanCar();}
}
外部系统调用:
public class MainTest {public static void main(String[] args) {AbstractCarFactory carFactory = new WulinRacingCarFactory();AbstractCar abstractCar = carFactory.newCar();abstractCar.run();carFactory = new WulinVanCarFactory();AbstractCar abstractCar1 = carFactory.newCar();abstractCar1.run();}
}
3.3 总结
此时我们发现如果我们有了一个新的RaceCar,我们不需要破坏原有的代码,只需要新创建一个RaceCarFactory,使其继承抽象工厂,后续别的系统调用时,我们就可以直接调用其工厂来进行使用即可。
但是,如果我们这个大工厂类,比不单单地只想创建出一个产品族的类,而是想创建出多个产品族的类该如何做呢?那么我们看到我们工厂方法形式已经实现不了了。
4. 抽象工厂(Abstract Factory)
4.1 简介
我们上述提到了我们这个工厂类不单单想让其创建一个产品族的产品,我们也想扩大规模创建更多的产品族,如Mask类,那么我们就可以采用面向对象的重要思想——抽象,我们可以对工厂类进一步抽象成一个新的工厂,这个工厂就是抽象工厂。
4.2 代码实现
抽象工厂类:
public abstract class WulinFactory {List<String> rules;abstract AbstractCar newCar();abstract AbstractMask newMask();
}
我们这个抽象工厂类,把我们此厂要创建的产品族类的方法全部定义后,那么后续的其他具体实现工厂即可直接实现其要创建的方法,另一个方法直接返回空即可,那么我们就可以在后续的子工厂再添加一个新的抽象层,
Car抽象工厂:
public abstract class WulinCarFactory extends WulinFactory{@Overrideabstract AbstractCar newCar();@OverrideAbstractMask newMask() {return null;}
}
Mask抽象工厂:
public abstract class WulinMaskFactory extends WulinFactory{@OverrideAbstractCar newCar() {return null;}abstract AbstractMask newMask();
}
可以发现每一个子工厂的抽象类为了保证后续工厂各司其职,只对后续的工厂提供了一个抽象方法,那么后续的代码也就和工厂方法类似了,这里就不写具体的代码实现了。
4.3 总结
抽象工厂其实就在工厂方法的基础上添加了一层新的抽象,其实这种设计模式在Java 主流Web开发框架中的Spring应用极为广泛,后续我也会持续更新Spring源码中在此模式下的具体应用。
5. 工厂模式的退化
当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。
6. 应用场景
- NumberFormat、SimpleDateFormat
- LoggerFactory:
- SqlSessionFactory:MyBatis BeanFactory:
- Spring的BeanFactory(就是为了造出bean)
- ......