定义
定义一个创建对象的接口、让子类决定实例化哪一个类, Factory Method 使一个类的实例化延迟到其子类。
结构和说明
示例代码
public class FactoryMethodDemo {
public static interface Product {
}
public static abstract class Creator {
protected abstract Product factoryMethod();
public void somOperation() {
// 通常在这些方法实现中需要调用工厂方法来获取 Product 对象
Product product = factoryMethod();
}
}
public static class ConcreteProduct implements Product {
}
public static class ConcreteCreator extends Creator {
@Override
protected Product factoryMethod() {
return new ConcreteProduct();
}
}
}
这里要注意一个问题,子类在实现这些抽象方法的时候,通常并不是真正地由子类来实现具体的功能,而是在子类的方法里面做选择,选择具体的产品实现对象。
父类里面,通常会有使用这些产品对象来实现一定的功能的方法,而且这些方法所实现的功能通常都是公共的功能,不管子类选择了何种具体的产品实现,这些方法的功能总是能正确执行。
模式讲解
- 谁来使用工厂方法创建的对象
是 Creator 中的其他方法在使用工厂方法创建的对象,虽然也可以把工厂方法创建的对象直接提供给 Creator 外部使用,但工厂方法模式的本意可,是由 Creator 对象内部的方法来使用工厂方法创建的对象,也就是说,工厂方法一般不提供给 Creator 外部使用。
客户端应该使用 Creator 对象,或者使用由 Creator 创建出来的对象。对于客户端使用 Creator 对象,这个时候工厂方法创建出来的对象,这个时候工厂方法创建出来的对象,是 Creator 中某些方法使用;对于使用那些由 Creator 创建出来的对象,这个时候工厂方法创建的对象,是构成客户端需要的对象的一部分。分别举例说明。
(1) 客户端使用 Creator 对象的情况
/**
* 客户端使用 Creator 对象的情况下, Creator 的基本实现
*/
public abstract class Creator1 {
/**
* 工厂方法,一般不对外
*
* @return 创建的产品对象
*/
protected abstract Product factoryMethod();
public void someOperation() {
// 在这里使用工厂方法
Product product = factoryMethod();
}
}
(2) 客户端使用 Creator 创建出来的对象
/**
* 客户端使用 Creator 来创建客户单需要的对象的情况下, Creator 的基本实现
*/
public abstract class Creator2 {
/**
* 工厂方法,一般不对外,创建一个部件对象
*
* @return 创建的产品对象,一般是另一个产品对象的部件
*/
protected abstract Product1 factoryMethod1();
/**
* 工厂方法,一般不对外,创建一个部件对象
*
* @return 创建的产品对象,一般是另一个产品对象的部件
*/
protected abstract Product2 factoryMethod2();
public Product createProduct() {
// 在这里使用工厂方法, 得到客户端所需对象的部件对象
Product1 p1 = factoryMethod1();
Product2 p2 = factoryMethod2();
// 工厂方法创建的对象是创建客户端对象所需要的
Product p = new ConcreteProduct();
p.setProduct1(p1);
p.setProduct2(p2);
return p;
}
}
小结一下: 在工厂方法模式里面,客户端要么使用 Creator 对象,要么使用 Creator 创建的对象,一般客户端不直接使用工厂方法。当然也可以直接把工厂方法暴露给客户端操作,但是一般不这么做。
调用顺序
客户端使用 Creator 对象的情况
客户端使用 Creator 创建出来的对象
参数化工厂
/**
* 1. 非抽象
*/
public static class Creator {
/**
* 2. 非抽象, 有默认实现
*
* @param type
* @return
*/
protected Product factoryMethod(int type) {
// 根据参数来选择 Product 实现
return null;
}
public void someOperatioin(int type) {
Product product = factoryMethod(type);
}
}
优缺点
优点
- 可以在不知具体实现的情况下编程
工厂方法模式可以让你在实现功能的时候,如果需要某个产品对象,只需要使用产品的接口即可,而无须关心具体的实现。选择具体实现的任务延迟到子类去完成。
- 更容易扩展对象的新版本
工厂方法给子类提供了一个挂钩,使得扩展新对象的版本非常容易。
另外这里提到的挂钩,就是我们常说的钩子方法(hook)
- 链接平行的类层次
工厂方法出了创造产品对象外,在链接平行的类层次上也大显身手。
缺点
- 具体产品对象和工厂方法的耦合性
在工厂方法模式中,工厂方法是需要创建产品对象的,也是需要选择具体的产品对象,并创建他们的实例,因此具体产品对象和工厂方法是耦合的。
思考
本质
延迟到子类来选择实现
对设计原则的体现
- 依赖倒置原则
何时选用
- 如果一个类需要创建某个接口的对象,但是又不知道具体的实现,这种情况可以选用工厂方法模式,把创建对象的工作延迟到子类中去实现。
- 如果一个类本身就希望由它的子类来创建所需的对象的时候,应该使用工厂方法模式。
相关模式
- 工厂方法模式和抽象工厂模式
这两个模式可以组合使用,具体的放到抽象工厂模式中去讲。
- 工厂方法模式和模版方法模式
这个模式外观类似,都有一个抽象类,然后由子类去提供一些实现,但是工厂方法模式的子类专注的是创建产品对象,而模版方法的子类专注的是为固定的算法骨架提供某些步骤的实现。
这两个模式可以组合使用,通常在模版方法里面,使用工厂方法来创建模版方法需要的对象。