一、定义
一个用于创建对象的接口,让子类决定实例化哪一个类。
工厂方法使一个类的实例化延迟到子类。
二、通用代码
- 抽象产品类
public abstract class Product{
public void method1(){
//业务逻辑
}
public abstract void method2();
}
- 具体产品类
public class ConcreteProduct1 extends Product{
public void method2(){
//业务逻辑1
}
}
public class ConcreteProduct2 extends Product{
public void method2(){
//业务逻辑2
}
}
- 抽象工厂类
public abstract class Creator(
//注:参数通常为String,Enum,Class等,也可为空
public abstract <T extends Product> T createProduct(Class<T> C);
}
- 具体工厂类
public class ConcreteCreator extends Creator{
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);
}
}
三、 优点
- 良好的封装性。代码结构清晰,调用者仅需知道类名,不需要管创建对象的过程如何如何。
- 优秀的扩展性
- 可以屏蔽产品类。只要接口保持不变,上层模块代码不发生改变,调用者无需在意产品类的变化。
- 典型的解耦框架
四、缺点
- 增加系统中类的数量,增加代码的复杂度
- 引入了抽象层,导致系统可读性较差
- 类层次过多,导致系统设计较为复杂
五、使用场景
- 生成对象的地方均可使用
- 原因:工厂模式是new一个对象的替代品
- 注意:增加工厂类会增加代码的复杂度,请结合实际情况,慎重考虑使用
- 需要灵活的,可扩展的框架
- 异构项目中
- 测试驱动开发的框架
场景:测试一个类A,需要把类A有关联的类B同时生产处理,可以使用工厂方法模式把类B虚拟处理,避免类A与类B的耦合。
但目前可以直接考虑JMock或EasyMock
六、扩展
-
简单工厂模式(静态工厂模式)
- 方法:去掉抽象工厂类,工厂类中的方法改为静态方法
- 优点:用法简单,调用简单,简化了类的创建过程
- 缺点:工厂类扩展难
-
多工厂模式
- 方法:给每个产品创建一个工厂抽象类
- 优点:符合单一职责原则,职责清晰;结构简单
- 缺点:对可扩展性和后期维护不友好
- 注:在实际的复杂应用中,一般采用多工厂方法,增加一个协调类,封装子工厂类,对高层模块提供统一的访问接口,避免调用者与各个子工厂交流
-
替代单例模式
-
延迟初始化
- 方法:在工厂类中定义一个Map容器,容纳产生的对象,已有的对象直接取出,没有则创建并放入Map中
- 优点:
- 保留需要再次被重用的对象
- 在对象初始化比较复杂的情况下,降低对象的产生和销毁带来的复杂性
- 扩展:控制某个产品类的最大实例化数量
- 注意:工厂类中的生产产品的方法需要使用synchronized关键字,防止线程不安全