我几天一直在修补这个想法,我想知道是否有其他人想过这样做。我想尝试创建一个ResourceBundle,我可以使用枚举来访问值。这种方法的好处是我的密钥定义得很好,希望我的IDE能够获取类型并为我自动完成变量名称。换句话说,我正在经历一种精致的ListResourceBundle。
基本上,这就是我所追求的......
我有一个枚举,其中包含各种类似的设置:
interface Bundle {
String getBundleName();
EnumResourceBundle<??????> getEnumResourceBundle();
}
enum Bundles implements Bundle {
BUNDLE1("com.example.Bundle1", Keys.class);
private final String bundleName;
private final EnumResouceBundle<??????> bundle;
/**
* I understand here I need to do some cast with ResourceBundle.getBundle(bundleName);
* in order to have it back-track through parents properly. I'm fiddling with this
* right now using either what I specified earlier (saving bundleName and then
* retrieving the ResourceBundle as needed), and saving a reference to the
* ResourceBundle.
*/
private <E extends Enum<E> & Key> Bundles(String bundleName, Class<E> clazz) {
this.bundleName = bundleName;
this.bundle = new EnumResourceBundle<??????>(clazz);
}
@Override
public String getBundleName() {
return bundleName;
}
@Override
public EnumResourceBundle<??????> getEnumResourceBundle() {
return bundle;
}
}
interface Key {
String getValue();
}
enum Keys implements Key {
KEY1("This is a key"),
KEY2("This is another key");
private final String value;
private Keys(String value) {
this.value = value;
}
@Override
public String getKey() {
return value;
}
}
class EnumResourceBundle<E extends Enum<E> & Key> extends ResourceBundle {
// Can also store Object in case we need it
private final EnumMap<E, Object> lookup;
public EnumResourceBundle(Class<E> clazz) {
lookup = new EnumMap<>(clazz);
}
public String getString(E key) {
return (String)lookup.get(key);
}
}
所以我的总体目标是让代码看起来像这样:
public static void main(String[] args) {
Bundles.CLIENT.getEnumResourceBundle().getString(Keys.KEY1);
Bundles.CLIENT.getEnumResourceBundle().getString(Keys.KEY2);
// or Bundles.CLIENT.getString(Keys.KEY1);
}
我还想为格式化替换提供支持(%s,%d,...)。
我意识到不可能从类中回溯一个类型,这对我没有帮助,因为我已经实例化了Bundles#bundle,所以我想知道我是否可以以某种方式声明EnumResourceBundle,其中泛型类型是已实现Key接口的枚举。任何想法,帮助或想法将不胜感激。在我诉诸命名常量之前,我真的很想看看我是否可以像这样工作。
更新: 我有一个想法,也许我也可以尝试更改EnumResourceBundle#getString(E)来取代一个Key,但这并不能保证它是枚举中指定的有效Key,或任何枚举。然后,我不确定在子EnumResourceBundle中使用父枚举键时该方法如何工作,所以也许Key是更好的选择。
答案 0 :(得分:2)
之前我做过类似的事情,但我反过来接近它,这很简单。
我刚刚创建了一个接受枚举的枚举转换器类,然后将枚举名称映射到属性文件中的值。
我使用了单个资源包,然后翻译看起来像(来自内存):
<T extends enum>String translate(T e) {
return resources.getString(e.getClass().getName()+"."+e.getName());
}
<T extends enum>String format(T e, Object... params) {
return MessageFormat.format(translate(e), params);
}
现在对于任何枚举,您只需在文件中添加一个字符串:
com.example.MyEnum.FOO = This is a foo
com.example.MyEnum.BAR = Bar this!
如果你想确保传递的类是正确的enum,你可以为这些枚举定义一个共享接口,或者你可以将它变成一个类,在类类型上定义T,然后生成它的实例对于您希望能够翻译的每个枚举。然后,您可以通过执行新的EnumFormatter()来为任何枚举创建翻译类。使format()
受保护将允许您通过在EnumFormatter中实现它来为每个枚举类型提供特定的可执行格式。
使用类的想法甚至可以让你更进一步,当你创建类时,你可以指定它的枚举和属性文件。然后,它可以立即扫描属性文件,并确保枚举中的每个值都有一个映射 - 如果缺少一个异常则抛出异常。这有助于确保及早检测属性文件中的任何缺失值。