Простой способ сохранить настройки приложения Java представлен текстовым файлом с расширением «.properties», содержащим идентификатор каждого параметра, связанного с конкретным значением (это может быть число, строка, дата и т. Д.) , C # использует аналогичный подход, но текстовый файл должен называться «App.config». В обоих случаях в исходном коде вы должны инициализировать определенный класс для чтения настроек: у этого класса есть метод, который возвращает значение (в виде строки), связанное с указанным идентификатором настройки.
// Java example
Properties config = new Properties();
config.load(...);
String valueStr = config.getProperty("listening-port");
// ...
// C# example
NameValueCollection setting = ConfigurationManager.AppSettings;
string valueStr = setting["listening-port"];
// ...
В обоих случаях мы должны проанализировать строки, загруженные из файла конфигурации, и назначить преобразованные значения связанным типизированным объектам (ошибки синтаксического анализа могут возникнуть на этом этапе). После шага синтаксического анализа мы должны убедиться, что значения настроек принадлежат определенной области действия: например, максимальный размер очереди должен быть положительным значением, некоторые значения могут быть связаны (пример: min <max ), и так далее.
Предположим, что приложение должно загрузить настройки сразу после его запуска: другими словами, первая операция, выполняемая приложением, заключается в загрузке настроек. Любые недопустимые значения параметров должны быть автоматически заменены значениями по умолчанию: если это происходит с группой связанных параметров, все эти параметры устанавливаются со значениями по умолчанию.
Самый простой способ выполнить эти операции - создать метод, который сначала анализирует все параметры, затем проверяет загруженные значения и, наконец, устанавливает любые значения по умолчанию. Однако обслуживание будет затруднено, если вы используете этот подход: по мере того, как количество параметров увеличивается при разработке приложения, становится все труднее обновлять код.
Чтобы решить эту проблему, я подумал об использовании шаблона Template Method следующим образом.
public abstract class Setting
{
protected abstract bool TryParseValues();
protected abstract bool CheckValues();
public abstract void SetDefaultValues();
/// <summary>
/// Template Method
/// </summary>
public bool TrySetValuesOrDefault()
{
if (!TryParseValues() || !CheckValues())
{
// parsing error or domain error
SetDefaultValues();
return false;
}
return true;
}
}
public class RangeSetting : Setting
{
private string minStr, maxStr;
private byte min, max;
public RangeSetting(string minStr, maxStr)
{
this.minStr = minStr;
this.maxStr = maxStr;
}
protected override bool TryParseValues()
{
return (byte.TryParse(minStr, out min)
&& byte.TryParse(maxStr, out max));
}
protected override bool CheckValues()
{
return (0 < min && min < max);
}
public override void SetDefaultValues()
{
min = 5;
max = 10;
}
}
Проблема в том, что таким образом нам нужно создать новый класс для каждого параметра, даже для одного значения. Существуют ли другие решения этой проблемы?
В итоге:
- Простота обслуживания: например, добавление одного или нескольких параметров.
- Расширяемость: первая версия приложения может считывать один файл конфигурации, но более поздние версии могут дать возможность многопользовательской настройки (администратор устанавливает базовую конфигурацию, пользователи могут устанавливать только определенные настройки и т. Д.).
- Объектно-ориентированный дизайн.
источник
Ответы:
По сути, внешний файл конфигурации кодируется как документ YAML. Затем он анализируется во время запуска приложения и сопоставляется с объектом конфигурации.
Конечный результат является надежным и, прежде всего, простым в управлении.
источник
Давайте рассмотрим это с двух точек зрения: API для получения значений конфигурации и формат хранения. Они часто связаны, но полезно рассмотреть их отдельно.
API конфигурации
Шаблонный метод шаблона очень общий, но я задаюсь вопросом, действительно ли вам нужна эта универсальность. Вам понадобится класс для каждого типа значения конфигурации. У вас действительно есть так много типов? Я предполагаю, что вы могли бы обойтись с помощью всего лишь нескольких: строк, целых чисел, чисел с плавающей запятой, логических и перечислений. Учитывая это, вы можете иметь
Config
класс с несколькими методами:(Я думаю, что я получил дженерики на этом последнем правильно.)
По сути, каждый метод знает, как обрабатывать строковое значение из файла конфигурации, обрабатывать ошибки и возвращать значение по умолчанию, если это необходимо. Проверка диапазона для числовых значений, вероятно, достаточно. Вы могли бы хотеть иметь перегрузки, которые пропускают значения диапазона, которые были бы эквивалентны предоставлению диапазона Integer.MIN_VALUE, Integer.MAX_VALUE. Enum - это безопасный для типов способ проверки строки по фиксированному набору строк.
Есть некоторые вещи, которые он не обрабатывает, такие как множественные значения, значения, которые взаимосвязаны, динамический поиск таблиц и т. Д. Вы можете написать для них специализированные процедуры анализа и проверки, но если это станет слишком сложным, я бы начал сомневаться пытаетесь ли вы сделать слишком много с файлом конфигурации.
Формат хранения
Файлы свойств Java прекрасно подходят для хранения отдельных пар ключ-значение, и они довольно хорошо поддерживают типы значений, которые я описал выше. Вы также можете рассмотреть другие форматы, такие как XML или JSON, но они, вероятно, излишни, если у вас нет вложенных или повторных данных. На данный момент это кажется далеко за пределами файла конфигурации ....
Теластин упомянул сериализованные объекты. Это возможно, хотя сериализация имеет свои трудности. Это двоичный файл, а не текстовый, поэтому трудно просматривать и редактировать значения. Вы должны иметь дело с совместимостью сериализации. Если в сериализованном вводе отсутствуют значения (например, вы добавили поле в класс Config и читаете его старую сериализованную форму), новые поля инициализируются как ноль / ноль. Вы должны написать логику, чтобы определить, следует ли заполнить какое-то другое значение по умолчанию. Но означает ли ноль отсутствие значения конфигурации, или оно было указано равным нулю? Теперь вы должны отладить эту логику. Наконец (не уверен, что это проблема), вам все равно может потребоваться проверка значений в сериализованном потоке объектов. Злоумышленник может (хотя и неудобно) незаметно изменять поток сериализованных объектов.
Я бы сказал, чтобы придерживаться свойств, если это вообще возможно.
источник
Config
класс и использовать подход , предложенный вами:getInt()
,getByte()
,getBoolean()
и т.д .. Продолжая эту идею, я сначала прочитал все значения , и я мог связать каждое значение флага (этот флаг равен false, если во время десериализации возникла проблема, например, ошибки синтаксического анализа). После этого я мог бы начать фазу проверки для всех загруженных значений и установить любые значения по умолчанию.Как я это сделал:
Инициализируйте все до значений по умолчанию.
Разбираем файл, сохраняя значения по ходу дела. Заданные места отвечают за обеспечение приемлемости значений, неправильные значения игнорируются (и, следовательно, сохраняют значение по умолчанию).
источник
Если все, что вам нужно, это простая конфигурация, я хотел бы сделать для нее простой старый класс. Он инициализирует значения по умолчанию и может быть загружен из файла приложением через встроенные классы сериализации. Затем приложение передает его всем, кто в этом нуждается. Никаких проблем с разбором или преобразованием, без перестановок с конфиг-строками, без лишнего мусора. И это делает конфигурации способ легче использовать для в-кода сценариев , где она должна быть сохранена / загружена с сервера или в качестве предварительных настроек, и способ проще в использовании модульных тестов.
источник
По крайней мере, в .NET вы можете довольно легко создавать собственные строго типизированные объекты конфигурации - быстрый пример см. В этой статье MSDN .
Подсказка: оберните ваш конфигурационный класс в интерфейс и дайте приложению поговорить об этом. Облегчает внедрение поддельной конфигурации для тестирования или получения прибыли.
источник
ConfigurationElement
класса может представлять группу значений, и для любого значения вы можете указать валидатор. Но если, например, я хотел представить элемент конфигурации, состоящий из четырех вероятностей, четыре значения вероятности коррелируют, так как их сумма должна быть равна 1. Как проверить этот элемент конфигурации?