我正在开发一个需要一些配置文件的Java应用程序,但我总是忘记属性名称,我发现为每个配置属性创建一个get方法并不合适。但是我发现它们对我们提供的返回类型很有用。
我想知道如何在设计良好的Java应用程序中管理配置,但我想知道如果我使用这样的枚举来做它是否是一个好习惯。我想如果他们在本地化文件中会变得多么复杂。但这个想法仍然引诱着我。
public enum Confs {
HLENGTH("hlength", Integer.class),
;
private String propertyName;
private Class type;
private Confs(String propertyName, Class type) {
this.propertyName = propertyName;
this.type = type;
}
public Object getVal(){
// This hash map is loaded in a singleton class which uses java Properties feature to read the configuration file
return MyLoadedConfigurationsSingleTon.getMap().get(this.propertyName);
}
}
无论如何,是不是有解决这个问题的标准解决方案?
答案 0 :(得分:3)
<强>键强>
这实际上取决于您的要求。这里有很多选择。对于简单的应用程序,我通常使用将任意配置键映射到值的东西。然后,可以将键的名称指定为字符串常量,例如,某处:
public static final String KEY_COLOR = "color";
public static final String KEY_SIZE = "size";
这当然会出现的问题,其中指定这些常量。您可以在某些全局共享位置指定它们(例如,在您的配置类中,或在某些特殊的常量值类中,或者甚至像您提议的那样enum
)。这样做的好处是可以让您在一个地方看到所有关键名称,从而轻松避免冲突。然而,这具有明显的主要缺点,即破坏模块性并强制所有类依赖于此密钥集合 - 添加/删除/移动对象现在需要您修改全局密钥集合。
您可以做的另一件事是将配置键名称定义为实际使用它们的类/包中的字符串常量。这不会打破模块化。但是,您现在可能会将密钥名称与其他不相关的类冲突。添加新密钥意味着您必须遍历使用配置的每个对象,并确保新密钥名称尚未使用。
然而,传统的Java解决方案是让密钥名称还包括使用它们的类的包(以及可能的类名)。 E.g:
package com.me.whatever;
public class Something {
static final String KEY_COLOR = "com.me.whatever.Something.color";
static final String KEY_SIZE = "com.me.whatever.Something.size";
}
package com.me.util;
public class Other {
static final String KEY_SIZE = "com.me.util.Other.size";
static final String KEY_GROUP = "com.me.util.Other.group";
}
有时仅指定包名称更有意义,如果这更能代表您的情况。
上述想法也适用于其他配置方案。例如。使用Preferences
API,可以从包名称派生密钥的路径。该API甚至提供systemNodeForPackage()
之类的东西来处理这个问题。
所以,只要做任何导致最清晰,最易维护的代码。在简单性,模块化和灵活性之间找到平衡点。对于简单的丢弃应用程序来说,打破“OOP”概念并将它们全部集中在一个地方是没有错的,只要你正在做的事情是清楚的。否则,将键值存储在主要使用的位置,并利用包名和类名来确保唯一性并避免关键名称空间污染。
请注意,如果在多个包之间拆分键名,enum
可能不一定是存储键名的最合适或最方便的数据类型。你当然可以想出一些聪明的系统来实现它的工作,但通常情况下,字符串常量既足够又易于使用。但是,如果您存储的不仅仅是密钥(例如值类型),enum
可能是一个合适的解决方案。
价值类型
顺便说一下,对于价值类型,你也有很多选择。您可以通过客户端类进行转换,而不是在配置方面强制执行 - 但是,当然,后者在很多情况下非常方便。
使用enum
的问题在于您实际上是在一个地方定义所有配置键(参见上文),并且在添加类时难以以模块化方式扩展可用的配置键集或者删除。
您可以创建一个通用配置密钥类,可以根据需要进行实例化,而不是使用固定的enum
,例如:
public class Conf {
public static class Key {
final String key;
final Class<?> type;
public Key (String key, Class<?> type) {
this.key = key;
this.type = type;
}
}
public Object getValue (Key key) {
...
}
}
通过使用泛型类型可以很容易地改进上述内容。
然后在您的客户端类中:
package com.me.whatever;
public class Something {
static final Conf.Key KEY_COLOR = new Conf.Key("com.me.whatever.Something.color", Color.class);
static final Conf.Key KEY_SIZE = new Conf.Key("com.me.whatever.Something.size", Integer.class);
}
再次说到关键名称:您甚至可以使包名称前缀添加为Conf.Key
的函数,类似于Preferences.systemNodeForPackage()
的工作原理,方法是将声明类的类型作为参数和提取包名称,以便上述声明成为,例如:
static final Conf.Key KEY_COLOR = new Conf.Key(Something.class, "color", Color.class);
<强>结论强>
我很喜欢,因为就像我说的那样,有无限的选择。我无法覆盖每个选项的每个案例,但希望你能得到这个想法。它更多的是以一种理智的方式接近它,而不是以一种特定的“正确”方式接近它。