前面我们已经学习了简单工厂模式和工厂方法模式,今天我们来学习一下抽象工厂模式;抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式是所有的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式的基本结构图如下所示。
图 1. 抽象工厂结构图
左边的等级结构代表工厂的等级结构,右边的等级结构代表两个不同产品的等级结构。此模式可以向客户端提供一个借口,使得客户端不用指定产品的具体类型的情况下,同时创建出多个产品对象。一般情况下我们使用工厂获取的对象是由不同产品的实体产品组成的混合体,这一点使用工厂方法模式基本上是无法实现的。
JBPM中的抽象工厂模式
从JBPM中实现的简单工厂模式和工厂方法模式,我们可以看到实际生产环境中对模式的实现与定义可能有很大的不同,这也说明设计模式只是给出一种能够使用的典型环境和实现结构,实际使用的时候要视具体的情况进行变通。JBPM对此模式的实现如下图所示
图 2. JBPM实现抽象工厂模式结构图
从图中可以看到JBPM同样没有完全照搬此模式给出的结构定义,此代码来自JBPM中的表达式实现部分,这部分有很多的类直接来自java的实现,关联关系比较乱,很容易掩盖抽象工厂模式的使用,不过只要我们将相关的类进行角色归类,那么一切就明朗可见了。
产品抽象类,就是FunctionMapper和ELResolver,他们都是来自java的表达式类库中的抽象类;
具体产品类,其中JbpmFunctionMapper作为唯一的产品类,继承并实现FunctionMapper;实现ELResolver的具体产品类,除了java类库实现的一些类,JBPM也实现了三个JbpmConstantsElResolver、JbpmEnvironmentElResolver、JbpmVariableElResolver。
其中最为关键的就是JbpmELContent,其继承了java类库中的ELContent,其作为产品的持有容器,使得我们创建JbpmELContent的时候,需要同时实例化两个不同类型的产品;这就为我们使用抽象工厂模式创造了条件,具体代码如下
public class JbpmElContext extends ELContext {
ELResolver elResolver;
FunctionMapper functionMapper;
public JbpmElContext(ELResolver elResolver, FunctionMapper functionMapper) {
this.elResolver = elResolver;
this.functionMapper = functionMapper;
}
public ELResolver getELResolver() {
return elResolver;
}
public FunctionMapper getFunctionMapper() {
return functionMapper;
}
public VariableMapper getVariableMapper() {
return null;
}
}
工厂基类,JbpmElFactory作为工厂基类,并没有直接的提供创建产品functionMapper和ELResolver的接口,而是直接提供了创建ELContext的接口,这样就将创建具体产品的实现推迟到工厂子类里,给予工厂子类充分的自由决策权。
public abstract class JbpmElFactory {
public static JbpmElFactory getJbpmElFactory() {
JbpmElFactory contextFactory = EnvironmentImpl.getFromCurrent(JbpmElFactory.class, false);
if (contextFactory==null) {
contextFactory = new JbpmElFactoryImpl();
}
return contextFactory;
}
public abstract ELContext createElContext();
public abstract ELContext createElContext(ScopeInstanceImpl scopeInstance);
public abstract ExpressionFactory createExpressionFactory();
}
具体工厂类,JbpmElFactoryImpl作为工厂子类,实现了父类创建ELContext的接口,同时也提供单独的接口,来分别完成对应产品的实例化,并最终将产品进行整合,最终将ELContext的对象实例提供给客户。
public class JbpmElFactoryImpl extends JbpmElFactory {
private static Log log = Log.getLog(JbpmElFactoryImpl.class.getName());
Class<?> functionClass = JstlFunction.class;
/** create ElContext used during parsing time */
public ELContext createElContext() {
return createCompositeResolver(null);
}
/** create ElContext used during evaluation time related to an execution */
public ELContext createElContext(ScopeInstanceImpl scopeInstance) {
return createCompositeResolver(scopeInstance);
}
protected ELContext createCompositeResolver(ScopeInstanceImpl scopeInstance) {
CompositeELResolver compositeELResolver = new CompositeELResolver();
if (scopeInstance!=null) {
compositeELResolver.add(new JbpmConstantsElResolver(scopeInstance));
compositeELResolver.add(new JbpmVariableElResolver(scopeInstance));
}
EnvironmentImpl environment = EnvironmentImpl.getCurrent();
if (environment!=null) {
compositeELResolver.add(new JbpmEnvironmentElResolver(environment));
}
addCdiResolver(compositeELResolver);
addBasicResolvers(compositeELResolver);
FunctionMapper functionMapper = createFunctionMapper();
return createElContext(compositeELResolver, functionMapper);
}
protected void addCdiResolver(CompositeELResolver compositeELResolver) {
BeanManager beanManager = getBeanManager();
if (beanManager!=null) {
ELResolver cdiResolver = beanManager.getELResolver();
if (cdiResolver!=null) {
compositeELResolver.add(cdiResolver);
log.debug("added cdi el resolver");
}
} else {
log.debug("no cdi bean manager available in jndi");
}
}
protected BeanManager getBeanManager() {
try {
InitialContext initialContext = new InitialContext();
return (BeanManager) initialContext.lookup("java:comp/BeanManager");
} catch (NamingException e) {
return null;
}
}
public ExpressionFactory createExpressionFactory() {
ExpressionFactory expressionFactory;
try {
expressionFactory = ExpressionFactory.newInstance();
} catch (NoSuchMethodError e) {
// to support previous version of el-api
expressionFactory = (ExpressionFactory) FactoryFinder.find(ExpressionFactory.class
.getName(),"de.odysseus.el.ExpressionFactoryImpl", null, "el.properties");
}
BeanManager beanManager = getBeanManager();
if (beanManager!=null) {
expressionFactory = beanManager.wrapExpressionFactory(expressionFactory);
}
return expressionFactory;
}
protected void addBasicResolvers(CompositeELResolver compositeELResolver) {
compositeELResolver.add(new ResourceBundleELResolver());
compositeELResolver.add(new MapELResolver());
compositeELResolver.add(new ListELResolver());
compositeELResolver.add(new ArrayELResolver());
compositeELResolver.add(new BeanELResolver());
}
protected FunctionMapper createFunctionMapper() {
return new JbpmFunctionMapper(functionClass);
}
protected JbpmElContext createElContext(CompositeELResolver compositeELResolver, FunctionMapper functionMapper) {
return new JbpmElContext(compositeELResolver, functionMapper);
}
}
抽象工厂模式的优劣
1. 不同的产品进行“组合”创建,客户端不必知道产品的具体类型。
2. 客户需要获取不同的产品“组合”,只需要简单的更改具体的工厂类。
3. 增加现有产品基类的子类,只需要新增相应的工厂类即可,此时很不好的遵循了开闭原则。
4. 增加新的产品系列,此时需要修改现有的工厂类,此时不能违反了开闭原则。