定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
/** 通用源码 */
// 抽象产品类
public abstract class Product{
// 产品类的公用方法
public void method1(){
// 业务逻辑
}
// 抽象方法
public abstract void method2();
}
// 具体产品类
public class ConcreteProduct1 extends Product{
@Override
public void method2(){
// 业务逻辑处理
}
}
public class ConcreteProduct2 extends Product{
@Override
public void method2(){
// 业务逻辑处理
}
}
// 抽象工厂类
public abstract class Creator{
// 创建一个产品对象,其输入参数可自行设置,通常为String、Enum、Class等,也可为空
public abstract <T extends Product> T createProduct(Class<T> c);
}
// 具体工厂类
public class ConcreteCreator extends creator {
@Override
public <T extends Product> T createProduct(Class<T> c){
Product product = null;
try{
product = (Product)Class.forName(c.getName()).newInstance();
} catch (Exception e){
// 异常处理
}
return (T)product;
}
}
// 使用场景
Public class Client{
public static void main(String[] args){
Creator creator = new ConcreteCreator();
Product product = creator.createProduct(ConcreteProduct1.class);
// 其他业务逻辑。
}
}
工厂方法模式的优点:
- 良好的封装性,代码结构清晰;
- 扩展性优秀;
- 屏蔽产品类;
- 典型的解耦框架,高层模块只需要感知产品的抽象类,其他实现不用关心,符合迪米特、依赖倒置、里氏替换。
工厂模式的使用场景:
- 所有需要产生新对象的地方都可以使用,但需要考虑是否会增加代码复杂度;
- 需要灵活、可扩展的框架时,可以考虑使用工厂方法模式;
- 可以用在异构项目当中;
- 可以使用在测试驱动开发的框架下(JMock&EasyMock的诞生使此场景弱化了,可直接使用JMock&EasyMock进行测试解耦)。
工厂模式的扩展
- 缩小为简单工厂模式:模块只需要一个工厂类,没必要使用抽象工厂,直接去掉继承抽象类,使用实际工厂类,并将产生对象的方法静态化(static);
- 升级为多个工厂类:当产品复杂的时候,所有产品放到一个工厂中进行初始化会使得代码结构不清晰,为使结构清晰,可以为每个产品定义一个创造者,然后调用者自己选择跟哪一个实际工厂进行关联。
- 替代单例模式:不允许使用new产生对象,提供一个工厂使用反射生成这个对象(那其他地方也可以这样产生这个对象,可修改构造器,防止被多次调用)
- 延迟初始化:一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用;其可降低对象的产生和销毁带来的复杂性。
// 延迟初始化示例代码
public class ProductFactory{
private static final Map<String, Product> prMap = new HashMap();
public static synchronized Product createProduct(String type) throws Exception{
Product product = null;
if (prMap.containsKey(type)){
product = prMap.get(type);
} else {
if (type.equals("Product1")) {
product = new ConcreteProduct1();
} else {
product = new ConcreteProduct2();
}
// 同时把对象放到缓存容器中
prMap.put(type, product);
}
return product;
}
}