大量のハードコードされたコンスタンを保持するクラスを使用するコードがあります。これは次のようになります。
class Constants{
public static final String name1 = "value1";
public static final String name2 = "value2";
public static final Integer value3 = 3;
... and so on
}
これらの定数は、コード内のあらゆる場所で次のように使用されます Constants.name1
.
今やらなければならないことは、構成ファイルでこれらの定数の値を指定できるようにすることです。 *.properties
ファイル。
私の質問は、できる限り少ないコードを書き換える必要がある、それを行うための最良の方法は何ですか?
単一の構成クラスを使用することを考えましたインスタンス化時にファイルからプロパティを読み取りますが、値のすべての静的呼び出しをそのクラスのインスタンスへの呼び出しに置き換える必要があり、既存のメソッドを変更してこの構成インスタンスをそれらに渡す必要があります。もっと良い方法はありますか?
回答:
回答№1は4これは、私が過去に使用したコードの一部です-これは、あなたの例に適合させることができます:
public enum Configuration {
PROPERTY1("property1.name", "default_value_1"),
PROPERTY2("property2.name", "default_value_2");
private final String key;
private String defaultValue;
Configuration(String key) {
this(key, NA);
}
Configuration(String key, String defaultValue) {
this.key = key;
this.defaultValue = defaultValue;
}
private final static Logger logger = LoggerFactory.getLogger(Configuration.class);
private final static String NA = "n.a.";
private final static String CONFIG_FILE = "properties/config.properties";
private final static String NOT_A_VALID_KEY = "Not a valid property key";
private final static Map<Configuration, String> configuration = new EnumMap<>(Configuration.class);
static {
readConfigurationFrom(CONFIG_FILE);
}
private static void readConfigurationFrom(String fileName) {
logger.info("Reading resource: {}", fileName);
try (InputStream resource = Configuration.class.getClassLoader().getResourceAsStream(fileName);) {
Properties properties = new Properties();
properties.load(resource); //throws a NPE if resource not founds
for (String key : properties.stringPropertyNames()) {
configuration.put(getConfigurationKey(key), properties.getProperty(key));
}
} catch (IllegalArgumentException | IOException | NullPointerException e) {
logger.error("Error while reading the properties file {}", fileName, e);
populateDefaultValues();
}
}
private static Configuration getConfigurationKey(String key) {
for (Configuration c : values()) {
if (c.key.equals(key)) {
return c;
}
}
throw new IllegalArgumentException(NOT_A_VALID_KEY + ": " + key);
}
private static void populateDefaultValues() {
for (Configuration c : values()) {
configuration.put(c, c.defaultValue);
}
}
/**
* @return the property corresponding to the key or null if not found
*/
public String get() {
return configuration.get(this);
}
}
回答№2の場合は3
を使用してファイルからプロパティをロードします Properties.load(...)
そして、それらのプロパティから定数を割り当てます。
class Constants{
public static final String name1;
public static final String name2;
public static final Integer value3;
static{
Properties p = new Properties();
try ( FileInputStream stream = new FileInputStream( new File("path/to/file.properties") )) {
p.load( stream );
}catch( Exception e ){
//handle exceptions
}
name1 = p.getProperty( "name1" );
name2 = p.getProperty( "name2" );
value3 = Integer.valueOf( p.getProperty( "value3" ) );
}
これは迅速で汚い解決策であり、多くの仮定をしていることに注意してください。個々の例外を処理することをお勧めします。また、 NumberFormatException
によってスローされる可能性があります Integer.valueOf(...)
構成が空であるか、数値ではない場合。
別の注意:実行時にプロパティを変更できるようにするために、いくつかの非静的または少なくとも非最終構成を試して使用することもできます。
編集:ストリームにautocloseを追加しましたが、Java 7より前はそれを自分で処理する必要があることに注意してください。
答え№3の2
簡単なハックとして、プロパティファイルを static
クラスの初期化子を使用すると、クラスフィールドの静的な性質をすぐに変更する必要はありませんが、いずれにしても時間をかけて変更することをお勧めします。
古い定数値をすべて保持する新しいクラスを作成します。これから、この構成オブジェクトを新しいコードに挿入します。
class NewConstants {
public final String name1;
public final String name2;
public final Integer value3;
... and so on
public NewConstants ( Properties props )
{
name1 = props.getProperty( "name1" );
...
}
}
今、あなたの古いリファクタリング Constants
クラス
class Constants (
public static final String name1;
public static final String name2;
public static final Integer value3;
static {
Properties props = new Poperties( );
props.load( ... );
NewConstants newConstants = new NewConstants( props );
name1 = newConstants.getName1( );
name2 = newConstants.getName2( );
...
}
}