原理
定义与类型
- 定义:由一个工厂对象决定创建出哪一种产品类的实例
- 类型:创建型,但不属于23种设计模式
注意:抽象工厂和工厂方法都是由简单工厂一步一步演进过来的
适用场景
- 工厂类负责创建的对象比较少
- 客户端(应用层)只知道传入工厂类的参数
对于如何创建对象(逻辑)不关心
优点与缺点
优点:
- 只需要传入一个正确的参数,就可以获取你所需要的对象而无须知道其创建的细节
工厂类中还可以有必要的判断逻辑,决定在什么时候创建哪一个产品的实例
缺点:
- 工厂类的职责相对过重,增加新的产品时,需要修改工厂类的判断逻辑,违背开闭原则
这些原则不能全部遵守,也不能不遵守,这是一个平衡的过程,根据实际的业务模型去进行选择 - 无法实现基于继承的等级结构
代码
背景:
比如目前有很多的编程语言的学习视频:java、python等等;对于生产视频的抽象方法,例如:java和python视频的生产过程会不一样。
实现我们的Video抽象类:
JavaVideo类与PythonVideo类均继承了Video抽象类:
在客户端(即应用层)进行调用:
我们可以发现显得有些麻烦,因为当我们想要调用PythonVideo的时候就会需要我们自己再去new PythonVideo一下,那么如何将整个的生产过程放到一个类中,让应用层不去依赖对应的具体实现类呢?这就是简单工厂的由来。
实现:
VideoFactory类:
Test类:
UML类图:
我们可以发现Test只依赖VideoFactory,具体的生产逻辑在VideoFactory当中
即Test直接找工厂,工厂直接进行生产,Test只管使用就行了
但随即也有缺点:如果现在需要新加一门课程,那么我们需要直接修改VideoFactory类的实现;即随着课程的扩展,类需要不断的进行修改
对于这个问题,可以通过反射来弥补简单工厂的扩展性:
Test类:
这样的设计就满足了开闭原则,我们在新增课程时不需要去改动工厂VideoFactory类了,只需要相对应的增加课程类即可
这是针对这种问题的一种处理方式,后续的工厂方法和抽象工厂是简单工厂的演进,也会有相对应的处理方式
jdk中体现
java.util.Calendar类,在private static Calendar createCalendar()方法中有这样一段代码:
与我们所实现的简单工厂的coding有异曲同工之处,都是进行简单的if判断,然后将对应的实现给返回
我们查看对应的UML类图:
Calendar是个抽象类,自身实现了对应的接口,同时又有对应的XXXCalendar类去继承他们并进行实现
其实在JDBC的代码中,我们去获取数据库连接的时候,对应的coding也是一种简单工厂的实现,我们通常会通过Class.forName(“”)把对应的mysql驱动给传入进来,如果是Oracle,就换成Oracle对应的驱动,这部分就是简单工厂的一种体现,即我们在上述代码中使用反射的方式进行改造代码的一种表现形式