Ну, на самом деле это не схема валидатора но в любом случае…
Мотивация
Я пишу библиотеку, которая представляет собой пользовательский интерфейс для работы с некоторыми электронными модулями. Каждый реальный модуль представлен в библиотеке соответствующим классом. Решил добавить возможность программировать модуль сразу с помощью config юридическое лицо. Также должна быть возможность читать текущая конфигурация из модуля. Также я хочу, чтобы пользователь мог сохранять (загружать) конфигурацию в (из) файл на диске, и эти данные должны быть удобочитаемыми и редактируемыми. Итак, я выбрал смерть JSON как объект конфигурации.
Итак, у моих классов есть следующие функции-члены:
void ReadConfig( json& config );
void WriteConfig( const json& config );
Как преимущество У меня есть полиморфный объект: мне не нужно много разных конфигураций для каждого класса.
Как недостаток ну … то же самое. Наличие такого полиморфного объекта делает невозможным проверку действий с неправильными конфигурациями во время компиляции, например, передачу конфигурации дискриминатора для программирования АЦП.
Решение
Я решил, что у любого настраиваемого модуля должна быть конфигурация по умолчанию (какая-то схема), значения которой, если таковые имеются, null
с. Например:
{
"name": "V2718",
"settings": {
"inputs": [
{
"led_polarity": null,
"polarity": null
},
{
"led_polarity": null,
"polarity": null
}
],
...
}
Значит конфиг правильный тогда и только тогда, когда он может быть получен из значения по умолчанию, используя только замену null
s. Как мне это проверить? Ответ Патч JSON.
Код
Вот код (см. Validate
функция-член). Каждый модуль-класс наследуется от UConfigurable
абстрактный класс. Конечно, я мог бы предоставить код для Validate
только функция, но я думаю, что весь заголовок более согласован.
UConfigurable.h
#ifndef V_PLUS_CONFIGURABLE_H
#define V_PLUS_CONFIGURABLE_H
#include <nlohmann/json.hpp>
#include <iostream>
namespace vmeplus
{
using json = nlohmann::json;
// Curiously recurring template pattern
template <typename T>
class UConfigurable
{
protected :
static json fDefaultConfig;
public :
UConfigurable() {};
virtual ~UConfigurable() {};
virtual void ReadConfig( nlohmann::json &config ) = 0;
virtual void WriteConfig( const nlohmann::json &config ) = 0;
static json GetDefaultConfig() { return fDefaultConfig; }
static bool Validate( const json& source );
};
template<typename T>
bool UConfigurable<T>::Validate( const json& source )
{
bool verdict = true;
json patch = json::diff( source, fDefaultConfig );
for( auto it = patch.begin(); it != patch.end(); ++it )
{
// key "op" MUST be in any patch according to
// https://datatracker.ietf.org/doc/html/rfc6902
// and its value MUST be one of the following
// "add", "remove", "replace", "move", "copy", or "test"
if( it->at("op") == "replace" )
{
// if "op" is "replace" then there MUST be the "value" key
if( not (it->at("value").is_null()) )
{
verdict = false;
break;
}
}
else
{
verdict = false;
break;
}
}
return verdict;
}
void WriteConfigToFile( const json& j, const std::string& path );
json ReadConfigFromFile( const std::string& path );
}
#endif
1 ответ
verdict = false;
break;
}
}
else
{
verdict = false;
break;
}
}
return verdict;
Только return false;
при обнаружении сбоя!
Затем return true;
если дойдете до конца.
Я предпочитаю только один
return
в функции.— LRDPRDX
@LRDPRDX Это очень похоже на C и не очень похоже на C ++.
— Мартин Йорк