抽象工厂模式
在struts国际化研究(一)中介绍了struts的默认国际化的默认实现类,但是在国际化的过程中,大多方法使用是MessageResources类中的方法,这里就是struts国际化的核心。
抽象工厂模式定义:提供一个接口,用于创建相关或依赖的对象家族,而不需要指定具体类。
MessageResources是一个抽象类(特殊的接口),其中仅有一个抽象方法public abstract String getMessage(Locale locale, String key),这个正式国际化的入口。
PropertyMessageResources(struts默认国际化类)继承MessageResources并实现的getMessage(Locale locale, String key)方法,当然自定义的国际化类也实现该接口,从而形成国际化文件家族。
public String getMessage(Locale locale, String key) {
if (log.isDebugEnabled()) {
log.debug("getMessage(" + locale + "," + key + ")");
}
// Initialize variables we will require
String localeKey = localeKey(locale);
String originalKey = messageKey(localeKey, key);
String messageKey = null;
String message = null;
int underscore = 0;
boolean addIt = false; // Add if not found under the original key
// Loop from specific to general Locales looking for this message
while (true) {
// Load this Locale's messages if we have not done so yet
loadLocale(localeKey);
// Check if we have this key for the current locale key
messageKey = messageKey(localeKey, key);
synchronized (messages) {
message = (String) messages.get(messageKey);
if (message != null) {
if (addIt) {
messages.put(originalKey, message);
}
return (message);
}
}
// Strip trailing modifiers to try a more general locale key
addIt = true;
underscore = localeKey.lastIndexOf("_");
if (underscore < 0) {
break;
}
localeKey = localeKey.substring(0, underscore);
}
// Try the default locale if the current locale is different
if (!defaultLocale.equals(locale)) {
localeKey = localeKey(defaultLocale);
messageKey = messageKey(localeKey, key);
loadLocale(localeKey);
synchronized (messages) {
message = (String) messages.get(messageKey);
if (message != null) {
messages.put(originalKey, message);
return (message);
}
}
}
// As a last resort, try the default Locale
localeKey = "";
messageKey = messageKey(localeKey, key);
loadLocale(localeKey);
synchronized (messages) {
message = (String) messages.get(messageKey);
if (message != null) {
messages.put(originalKey, message);
return (message);
}
}
// Return an appropriate error indication
if (returnNull) {
return (null);
} else {
return ("???" + messageKey(locale, key) + "???");
}
}
工厂方法模式
工厂方法模式:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
struts的工厂类MessageResourcesFactory,他是一个抽象类,包含一个抽象方法public abstract MessageResources createResources(String config),它的作用正如起名创建资源,怎么创建?看默认实现类。
MessageResourcesFactory的factoryClass指定了默认实现类PropertyMessageResourcesFactory
protected static String factoryClass = "org.apache.struts.util.PropertyMessageResourcesFactory";
PropertyMessageResourcesFactory很简单,就一个方法
public MessageResources createResources(String config) {
return new PropertyMessageResources(this, config, this.returnNull);
}
现在看一下struts是如何运用这个工程类创建MessageResources
struts的核心加载类是ActionServlet,他的initModuleMessageResources(ModuleConfig config)方法对国际化类进行初始化
protected void initModuleMessageResources(ModuleConfig config)
throws ServletException {
MessageResourcesConfig mrcs[] = config.findMessageResourcesConfigs();
for (int i = 0; i < mrcs.length; i++) {
if ((mrcs[i].getFactory() == null)
|| (mrcs[i].getParameter() == null)) {
continue;
}
if (log.isDebugEnabled()) {
log.debug(
"Initializing module path '"
+ config.getPrefix()
+ "' message resources from '"
+ mrcs[i].getParameter()
+ "'");
}
// 读取struts-config.xml中message-resources的属性
String factory = mrcs[i].getFactory();
// 该方法将覆盖factoryClass值(factoryClass上文中提到,工厂初始化类路径)
MessageResourcesFactory.setFactoryClass(factory);
// 调用createResources方法了,默认使用的是PropertyMessageResourcesFactory的,如果在struts-config.xml中定义了工厂类,这里将使用用户自定义的创建方法
MessageResourcesFactory factoryObject =
MessageResourcesFactory.createFactory();
factoryObject.setConfig(mrcs[i]);
// 通过factory创建MessageResources后,设置基本属性,这些属性是抽象工厂创建国际化家族所需的基本属性
MessageResources resources =
factoryObject.createResources(mrcs[i].getParameter());
resources.setReturnNull(mrcs[i].getNull());
resources.setEscape(mrcs[i].isEscape());
getServletContext().setAttribute(
mrcs[i].getKey() + config.getPrefix(),
resources);
}
}
这里还有一个实现细节需要注意PropertyMessageResourcesFactory的createResources方法在创建MessageResources的同时,将自己注入到了新创建的MesageResources中 ,MessageResources可以通过getFactory()方法轻松获取工厂类。