工厂方法模式
既然已经有了简单工厂模型了,为什么还有一个工厂方法模型呢?其实工厂方法模型就是为了解决简单工厂模型的缺点而产生的。简单工厂模型的缺点有哪些可以看这里:《浅谈简单工厂方法模式》,在此我们就不细说了。
总之,为了解决简单工厂模式的问题,我们又有了一种新的模式:工厂方法模式。
工厂方法模式的介绍
工厂方法模型,又称为多态性工厂模型,在工厂方法模型中,核心的工厂类不再负责所有的产品的创建,而是将具体实例化的工作交给了子类完成。该核心工厂类成为一个抽象工厂角色,作用是给具体的工厂子类必须实现的接口,不接触具体实例化哪些产品的细节。
解决了哪些问题
- 在简单工厂模型中,一旦添加新的产品类型就需要修改工厂类的逻辑。这违背了‘开放-闭合原则“
- 而在工厂方法模型中,将具体的实例化操作放在了工厂子类中实现,工厂类成为一个抽象的类,不需要实现具体的细节操作,那么当有新的产品类型时,无需修改工厂类,只需要添加一个工厂子类就行了,这样符合“开闭原则”。
模式组成
角色 | 关系 | 作用 |
---|---|---|
Product(抽象产品) | 具体产品的父类 | 描述产品的公共接口 |
ConcreteProduct(具体产品) | 抽象产品的子类;工厂类创建的目标类 | 描述具体生产的产品 |
Creator(抽象工厂) | 具体工厂的父类 | 描述具体工厂的公共接口 |
ConcreteCreator(具体工厂) | 具体工厂的父类 | 描述具体工厂;实现FactoryMethod工厂方法创建产品的实例 |
表述代码
我们先实现抽象产品类
/**
* 抽象产品类
* @author lishanlei
*
*/
public abstract class Product {
//产品类的公共方法
public void method1() {
}
public abstract void method2();
}
有了抽象产品类还不行,我们还需要具体的产品
ConcreteProduct1:
public class ConcreteProduct1 extends Product {
public void method2() {
//业务逻辑处理
System.out.println("this is product 1...");
}
}
ConcreteProduct2:
public class ConcreteProduct2 extends Product {
public void method2() {
//业务逻辑处理
System.out.println("this is product 2...");
}
}
现在我们定义一个抽象的工厂类,让它声明带实现的接口:
/**
* 抽象工厂类
* @author lishanlei
*
*/
public abstract class Creator {
public abstract <T extends Product> T createProduct(Class<T> c);
}
实现具体工厂类:
public class ConcreCreator extends Creator {
@Override
public <T extends Product> T createProduct(Class<T> c) {
// TODO Auto-generated method stub
Product product = null;
try {
product = (Product)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
//异常处理
}
return (T)product;
}
}
我们的客户端:
/**
* 场景类
* @author lishanlei
*
*/
public class Client {
public static void main(String[] args) {
Creator creator = new ConcreCreator();
Product product = creator.createProduct(ConcreteProduct2.class);
product.method2();
/**
* 继续业务处理
*/
}
}
运行结果:
this is product 2...
工厂方法模型的优点
- 更加符合开闭原则
- 新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可
- 不使用静态工厂方法,可以形成基于继承的等级结构
- 简单工厂模式的工厂类使用静态工厂方法
- 具有良好的封闭性和可扩展性,代码的结构更加清晰
工厂方法模型的缺点
- 增加新产品类型时,除了增加新产品类,还需要增加具体的工厂类,使得系统类的数目成对增加,一定程度上增加了系统的复杂度
- 虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类
工厂方法模型的使用场景
- 在所有需要生成对象的地方都可以使用(需要慎重考虑是否值得使用)
- 需要灵活的、可扩展的框架时
- 可以使用在异构项目中
- 在测试驱动开发的框架下使用
工厂方法模式的扩展
替代单例模式
单例模式的核心要求就是在内存中只有一个对象,通过工厂方法模式也可以只在内存中生产一个对象
Singleton定义一个private的无参数构造函数,目的是不允许通过new来创建一个对象
public class Singleton {
private Singleton() {
}
public void doSomething() {
//业务处理
System.out.println("业务处理中...");
}
}
Singleton保证了不能通过正常的渠道来创建一个对象,那么SingletonFactory如何建立一个单例对象呢?可以通过反射方式创建
import java.lang.reflect.Constructor;
public class SingletonFactory {
private static Singleton singleton;
static {
try {
Class c = Class.forName(Singleton.class.getName());
Constructor constructor = c.getDeclaredConstructor();
constructor.setAccessible(true);
singleton = (Singleton)constructor.newInstance();
} catch (Exception e) {
//异常处理
}
}
public static Singleton getSingleton() {
return singleton;
}
}
这样在项目中可以产生一个单例构造器,所有需要产生单例的类都遵循一定的规则,然后只要输入一个类型就可以获得唯一的一个实例。
延迟初始化
什么是延迟初始化?一个对象被消费完毕后,并不立即释放,工厂类保持其初始状态,等待再次被使用,延迟初始化是工厂方法模式的一个扩展应用。
//抽象产品类
public abstract class Product {
public abstract void method();
}
ConcreteProduct:
public class ConcreteProduct1 extends Product {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("product 1...");
}
}
public class ConcreteProduct2 extends Product {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("product 2...");
}
}
工厂类:
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;
}
}