Эффективное кодирование управления параметрами с переменными типами в Java - PullRequest
4 голосов
/ 14 февраля 2012

В настоящее время я реализую симуляцию на Java, которая требует ввода около 30 различных параметров.В конце концов, я хочу иметь возможность читать эти параметры из файла, а также из графического интерфейса, но сейчас я сосредоточен только на вводе файла.Для моего моделирования требуются параметры разных типов: строки, целые и двойные числа, и в настоящее время я имею их в качестве полей для моделирования, например:

private String simName;
private int initialPopulationSize;
private double replacementRate;

Поскольку эти параметры не все одного типа, я не могу их сохранитьв массиве, и я должен прочитать каждый в отдельности, используя один и тот же вид кода около 30 раз.Пример для трех параметров:

//scanner set up and reading each line, looking for "(key)=(param)" regex matches
//if statement to check each param name against the key matched in file. Store param in that field if the name matches.
String key = m.group(1);
if (key.equals(PKEY_SIM_NAME)) {
    if (simNameSet) {
        throw new IllegalStateException("multiple values for simulation name");
    }
    this.simName = m.group(2);
    simNameSet = true;

} else if (key.equals(PKEY_INITIAL_SIZE)) {
    if (initialSizeSet) {
        throw new IllegalStateException("multiple values for initial population size");
    }
    this.initialPopulationSize = Integer.parseInt(m.group(2));
    initialPopulationSize = true;

 } else if (key.equals(PKEY_MUT_REPLACEMENT)) {
    if (replacementRateSet) {
        throw new IllegalStateException("multiple values for replacement rate");
    }
    this.replacementRate = Double.parseDouble(m.group(2));
    replacementRateSet = true;
 }
    //Add nauseum for each parameter.....

Так что в настоящее время у меня есть длинный и неудобный метод для чтения параметров, и мне, вероятно, потребуется снова сделать то же самое для чтения из графического интерфейса.

Лучшая альтернатива, о которой я подумал, - это сначала прочитать все в строковые поля.Таким образом, я могу написать несколько простых строк для чтения при использовании карты.Примерно так (непроверенный код):

//This time with a paramMap<String, String>, scanner set up as before
if (!paramMap.containsKey(key)) {
    paramMap.put(key, m.group(2));
}
else{
    throw new IllegalStateException("multiple values for initial population size");
}

Однако это будет неудобно, когда речь заходит об использовании этих параметров с карты, так как мне придется приводить не-строковые параметры всякий раз, когда я хочуиспользовать их.

На данный момент я чувствую, что это мой лучший подход.Я хочу знать, может ли кто-нибудь более опытный придумать более эффективную стратегию для решения подобных ситуаций, прежде чем я продолжу.

Ответы [ 4 ]

2 голосов
/ 14 февраля 2012

Разбор таких файлов - плохая идея. Это уже сделано для вас!

Свойства

Механизм, который вы можете использовать, называется "свойствами" в Java. Это обычный текстовый файл, содержащий пары ключ-значение, как вы уже описали. Обычно имеет расширение *.properties.

Вам не нужно использовать Spring или любой другой фреймворк, так как он является частью обычного JDK. Так что не стесняйтесь использовать его для своего проекта!

Хотите быть в безопасности? Используйте настройки!

если вы хотите быть безопасным для типов, используйте вместо этого «настройки». Preferences API - это расширение обычного API Properties, которое гарантирует вам правильный тип требуемого свойства.

Документация

Использовать все вместе очень просто. Я не хочу повторять документацию, поэтому, пожалуйста, проверьте эти два ресурса: API свойств , API настроек

1 голос
/ 14 февраля 2012

Вы можете определить базовый класс параметров или интерфейс, например:

interface Parameter {
    void parse(String s);
    Object getValue();
    ...
}

и класс для каждого типа параметра, который вы хотите иметь, например, IntParameter, DoubleParameter, StringParameter. Вот эскиз IntParameter:

class IntParameter implements Parameter {
    private int value;

    public void parse(String s) {
        value = Integer.parseInt(s);
    }

    public Object getValue() {
        return value;
    }
    ...
}

Затем вы можете сохранить свои параметры в Map<String, Parameter> и заполнить их различными источниками, такими как параметры командной строки или свойства.


Более безопасное для типов, но запутанное решение может быть достигнуто, если вы не сохраняете значение в объектах параметров, а делаете параметры статическими объектами, которые используются для доступа к их значениям. Это показано на следующем примере:

abstract class Parameter {
    private String name;

    public Parameter(String name) {
        this.name = name;
    }

    public abstract Object parse(String s);
}

class IntParameter extends Parameter {
    public static final IntParameter ANSWER = new IntParameter("answer");
    // Add more options here.

    public IntParameter(String name) { super(name); }

    public Object parse(String s) {
        return Integer.parseInt(s);
    }
}

class Parameters {
    private Map<Parameter, Object> params = new HashMap<Parameter, Object>();

    public int get(IntParameter p) {
        return (Integer)params.get(p);
    }

    public void put(IntParameter p, int value) {
        params.put(p, value);
    }

    public void putString(Parameter p, String value) {
        params.put(p, p.parse(value));
    }
}

Это позволяет вам получить доступ к параметру безопасным способом:

Parameters params = new Parameters();
params.putString(IntParameter.ANSWER, "42"); // parse and store the value
int value = p.get(IntParameter.ANSWER);

Решение может быть распространено на другие типы.

0 голосов
/ 08 октября 2012

Упомянутая вами проблема является одной из основных причин, по которой я инициировал и поддерживаю инструмент под названием InPUT .Preferences API будет работать для вашего простого примера, но он по умолчанию не предлагает проверку содержимого, диапазонов значений или обработку непримитивных типов (кроме Strings).Если вы имеете дело с симуляциями или оптимизацией, вы можете читать дальше.

Вы можете определить свои параметры в дескрипторе пространства разработки XML следующим образом:

<SParam id="simName" type="String"/>
<NParam id="initialPopulationSize" type="integer" inclMin="10" inclMax="100"/>
<NParam id="replacementRate" type="double" inclMin="0.3" inclMax="0.7"/>

NParam (числовой) стоитдля примитивных параметров SParam (структурный) для параметров типа, когда речь идет о Java.

Ваша конфигурация (скажем, "config.xml") теперь может содержать следующие значения:

<SValue id="simName" value="someName"/>
<NValue id="initialPopulationSize" value="20"/>
<NValue id="replacementRate" value="0.42"/>

Из кода все, что вы делаете, это звоните:

Design input = new Design("config.xml");
String simName = input.get("simName");
int initialPopulationSize = input.get("initialPopulationSize");
double replacementRate = input.get("replacementRate");

InPUT гарантирует, что сопоставления соответствуют вашим дескрипторам.После того, как вы это настроите, вы можете добавлять / удалять, изменять альтернативы по своему усмотрению, не касаясь кода.Вы можете использовать его для вставки сложных вложенных классов (см. Главная страница InPUT, Пример ) в дескрипторе сопоставления кода или для определения отношений между числовыми значениями в дескрипторе параметра (например, размер элиты всегда меньше размера популяции).).Вы также можете создавать дизайны в произвольном порядке относительно пространства дизайна (например, чтобы найти оптимальные настройки параметров).Задача состоит в том, чтобы сделать этот инструмент доступным для различных языков программирования, для облегчения языкового обмена экспериментальными дескрипторами (C ++ находится в стадии разработки).Различные примеры Java уже можно найти здесь .

0 голосов
/ 14 февраля 2012

Вы можете использовать файл свойств для вашей ситуации. Файл свойств состоит из пар ключ / пара. Хорошая полезность для этого подхода - использование весны. образец:

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

         <property name="locations">
                  <list>
                     <value>[your-path-1]</value/>
                     <value>[your-path-2]</value/>
                  </list>
         </property>
    </bean> 

и для чтения ключа / значения:

    <bean id="pum"
            class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
        <property name="persistenceXmlLocations" value="${your-key-1}"/>
    </bean>

Значение пружины, установленное в your-key-1 key persistenceXmlLocations member. Хорошим преимуществом использования пружины является приведение типа , собственный тип преобразования свойства Spring к типу переменной.

...