Мне нужно реализовать функцию для программы, которая вычисляет метрики на основе предварительно определенных мер с требованием, чтобы добавление новой метрики (и / или меры) требовало минимальных изменений уровня кода. Вот как я это сделал:
class Measure { // clas to hold the measures
Integer id;
String name;
Long value;
// necessary getters and setters
}
Эти меры извлекаются из БД MySQL.
// the measures stored in an ArrayList of objects of the above Measure class
[
{
"id": 1,
"name": "Displacement",
"value": 200
},
{
"id": 2,
"name":"Time",
"value": 120
},
{
"id":3,
"name":"Mass",
"value": 233
},
{
"id":4,
"name": "Acceleration",
"value": 9.81
},
{
"id": 5,
"name":"Speed of Light",
"value": 300000000
}
]
Мне нужно получить такие метрики, как: Velocity (Displacement/Time)
, Force (Mass * Acceleration)
и Energy (Mass * Speed of Light^2)
Я реализовал следующий JSON, в котором я определил вышеупомянутые формулы:
[
{
"title": "Velocity",
"unit": "m/s",
"formula": "( displacement / time )"
},
{
"title": "Force",
"unit": "N",
"formula": "( mass * acceleration )"
},
{
"title": "Energy",
"unit": "J",
"formula": "( mass * speed_of_light * speed_of_light )"
}
]
Затем я вычисляю метрики следующим образом:
class Evaluator {
ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("js");
public Evaluator(List<Measure> measures) {
measures.forEach(measure -> {
String fieldName = measure.getName().replace(" ", "_").toLowerCase(); // convert Speed of Light -> speed_of_light etc
engine.put(fieldName, Double.parseDouble(measure.getValue()));
})
}
public void formula(String formula) throws Exception {
engine.eval("function calculateMetric() { return " + formula +" }");
}
public Object evaluate() throws ScriptException {
return engine.eval("calculateMetric()");
}
}
Приведенный выше класс используется для загрузки каждой формулы в Script Engine, а затем для вычисления значения метрики на основе предоставленной формулы.
// load JSON file into JsonArray
JsonArray formulae = parseIntoJsonArray(FileUtils.getContent("formulae.json"));
Evaluator evaluator = new Evaluator(measures);
for (Object formula : formulae) {
JsonObject jsonObj = (JsonObject) formula;
evaluator.formula(jsonObj.get("formula").getAsString());
Double metricVal = Double.parseDouble(evaluator.evaluate().toString());
// do stuff with value
}
Код работает, как и ожидалось. Я хочу знать, делаю ли я что-то неправильно, что может повлиять на программу в долгосрочной перспективе / если что-то не является наилучшей практикой / если есть лучший способ / более простой способ сделать то же самое.
Этот вопростесно связанный с вопросом , который я отправил вчера. Вроде вторая часть.