1.产生背景
- 为什么需要工厂方法
上一节我们了解了简单工厂,它实现了创建一个抽象(接口、类)多实例的解决方案,基本满足了对象的创建,那么为什么还需要工厂方法模式?
任何事物的产生,一定有它的原因,简单来说,一定是它解决了前人未解决的某个问题或者缺陷;
现在来看看简单工厂有哪些缺陷:
pulic interface SimpleInf{
void doSomething();
}
public class SimpleObj_1 implements SimpleInf{
public void doSomething(){
xxxxxx
}
}
public class SimpleObj_2 implements SimpleInf{
public void doSomething(){
xxxxxx
}
}
public class SimpleFactory{
public static SimpleInf createObj(int type){
if(type == 1){
return new SimpleObj_1();
}else if(type == 2){
return new SimpleObj_2();
}else{
return null;
}
}
}
public class Client{
public void myMethod(){
SimpleInf obj = SimpleFactory.createObj(1);
obj.doSomething();
}
}
从上面代码可以看出简单工厂有以下特点:
- 可以创建一个抽像的一系列对象
- 可以创建一个具体类的多个对象(调用一次创建一个)
- 客户使用简单(判断逻辑与初始化逻辑,全封装在工厂内)
- 静态方法(具有工具类性质)
从以上的特点可以分析出,它有一个重要缺陷:
难以扩展
- 静态方法:
无法重载,因此也无法通过继承或实现的方式扩展; - 判断逻辑下沉:
虽然把复杂逻辑抽象到工厂内,方便外部使用,但是把判断逻辑下沉到底层代码,导致工厂逻辑复杂度上升,每次新增一个类,就必须修改工厂,违背了“开闭原则”
2.概念
一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类
概念过于晦涩,暂且不用理会;
3.目的
解决简单工厂难以扩展的缺点
4.解决方案
本质:把简单工厂中,if else 部分抽像到具体工厂类;每个工厂只创建一个具体类的实例;以方便以后扩展;
也即:封装类中不变的部分,提取其中个性化善变的部分为独立类(策略化)
- 去除静态方法
- 工厂抽象化
- 判断逻辑策略化
通过上面的分析,我们知道简单工厂难以扩展最重要的原因是:工厂中的方法不能重载、判断逻辑下沉; 因此,只要解决了这两个问题就可以了;
重载:通过类继承或接口化,同时去除静态方法,就可以实现;
策略化:把一个个If - else判断的代码块,拆分到工厂实现类中,每个工厂只负责一个类的实例创建;
判断逻辑上浮: 把if - else上升到客户,由客户来做判断;
通过上图,我们把简单工厂改造成了工厂方法模式,把if -else抽像成一个个策略,并迁移到每个具体工厂类,可是if else 应该在什么时间判断,或者客户怎么使用呢?
public class client{
public void doSomethind(int type){
//判断逻辑返还给客户
MethodFactory factory = null;
if(type == 1){
factory = new MethodFactory_1();
}else if(type == 2){
factory = new MethodFactory_2();
}
//目标实例,仍然由工厂创建
SimpleInf obj =factory.createObj();
obj.doSomething();
}
}
5. 类图
6.优缺点
优点:
无论它有什么缺点,暂且放下,先来看看其中的优点:
- 判断逻辑上浮(到客户层),简化工厂逻辑
- 判断逻辑策略化,每个工厂只负责一个具体的实例创建,职责单一
- 判断逻辑策略化,扩展性强,每增加一个具体类,只需要实现对应的工厂即要,不需要修改原来的工厂
- 工厂抽象化(接口、抽像类),对外提供统一操作入口
最核心的目的:就是增强了工厂的可扩展性;
缺点:
看到上面的代码,是否发现,判断逻辑的上浮,又回到了“简单工厂模式”之前的状态;推翻了“简单工厂模式”,也推翻了它带来的优点和好处;
同时,我们提到了策略化,那么它跟策略模式又有什么区别;
客户使用复杂化
原本使用“简单工厂”封装对象创建的逻辑判断,现在客户创建对象,必须先判断并选择性创建对应的工厂,然后再使用此工厂创建对应的业务对象;与策略模式区别
这个称不上缺点,既然提到了“策略”,就对比一下他们之间的区别;
本质上,他们的实现方式没有任何区别,只是目的不同;
工厂方法的目的是:创建对象;重在对象的创建、初始化、装配;
策略模式的目的是:封装逻辑;重在逻辑,可以有返回值,也可以没有;
解释:
工厂方法模式,确实推翻了简单工厂模式;因为每种解决方案都不会十全十美,一定有所取舍;因此工厂方法模式在 “使用方便” 与 “扩展性” 之间,倾向了后者;
在我们的例子中,对象的创建逻辑都非常简单,所以对比不出不同模式的优点,而现实中,正是因为对象的创建过于复杂,才使用工厂,因此面对复杂的创建逻辑,客户的方便性的重要性要低很多;
同时,在实际编程中,可以通过IOC等方式解决客户的使用过程中的逻辑判断;
7.现实场景
spring框架的中BeanFactory是使用工厂方法模式的最佳案例;
通过BeanFactory接口,抽像对外统一入口;
通过ConfigurableBeanFactory、ClassPathXmlApplicationContext等各种实现类,扩展了不同场景下的具体工厂;