1、上下文及问题
有些对象的实例化比较复杂,比如读哪些配置文件,按哪些步骤初始化等等,这种问题,通常使用工厂方法,来对调用者屏蔽对象的创建逻辑。
2、常见场景
(1)需要对对象的实例进行管理的,比如统计/限制实例个数、实例回收等等,可以交由工厂来管理,比如数据库连接池
(2)多线程情况下,通常需要保证对象的不能够发布逃逸,就是在构造器初始化中将未实例化完成的对象发布出去,比如赋值给外部对象,或者在构造器开线程去访问等等,容易出现问题,因而可以用工厂方法,确保对象构造完后再加上某些必要的步骤之后才发布对象。
(3)如果一个类本身希望由子类来实例化,则很明显的要使用工厂方法
(4)数据库连接池、线程池、ThreadLocal
3、解决方式
(1)使用继承的方式解决,类的实例化延迟到具体的子类
4、模式抽象图
5、代码示例
(1)UML类图代码示例
Product及其实现类
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 抽象产品类
*/
public abstract class Product {
//产品类的公共方法
public void method1(){
//业务逻辑处理
}
//抽象方法1
public abstract void method2();
}
public class ConcreteProduct1 extends Product {
public void method2() {
//业务逻辑处理
}
}
public class ConcreteProduct2 extends Product {
public void method2() {
//业务逻辑处理
}
}
工厂及其实现类
public abstract class Factory{
/*
* 创建一个产品对象,其输入参数类型可以自行设置
* 通常为String、Enum、Class等,当然也可以为空
*/
public abstract <T extends Product> T createProduct(Class<T> c);
}
public class ConcreteFactory extends Factory {
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) {
Factory factory= new ConcreteFactory();
Product product = factory.createProduct(ConcreteProduct1.class);
/*
* 继续业务处理
*/
}
}
(2)外部利用反射产生单例
public class Singleton {
//不允许通过new产生一个对象
private Singleton(){
}
public void doSomething(){
//业务处理
}
}
外部反射产生单例
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
*/
public class SingletonFactory {
private static Singleton singleton;
static{
try {
Class cl= Class.forName(Singleton.class.getName());
//获得无参构造
Constructor constructor=cl.getDeclaredConstructor();
//设置无参构造是可访问的
constructor.setAccessible(true);
//产生一个实例对象
singleton = (Singleton)constructor.newInstance();
} catch (Exception e) {
//异常处理
}
}
public static Singleton getSingleton(){
return singleton;
}
}
客户端调用
public class Client {
public static void main(String[] args) {
SingletonFactory.getSingleton().doSomething();
}
}
(3)缓存示例
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
*/
public class Factory {
private static final Map<String,Product> prMap = new HashMap();
public static synchronized Product createProduct(String type) throws Exception{
Product product =null;
//如果Map中已经有这个对象
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;
}
}