2

I need to implement a feature for a program that calculates metrics based on predefined measures with the requirement that the addition of a new metric (and/or measure) should require minimal code level changes. This is how I have done it:

class Measure { // clas to hold the measures
    Integer id;
    String name;
    Long value;

    // necessary getters and setters
}

These measures are retrieved from a MySQL DB.

// 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
    }
]

I need to get metrics such as the following: Velocity (Displacement/Time), Force (Mass * Acceleration) and Energy (Mass * Speed of Light^2)

I implemented the following JSON in which I have defined the above formulae:

[
    {
        "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 )"
    }
]

I then calculate metrics in the following way:

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()");
    }
}

The above class is used to load each formula into the Script Engine and then calculate the metric value based on the formula provided.

// 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
}

The code works as expected. I want to know if I am doing anything wrong that could affect the program in the long run/if anything is not best practice/if there is a better way/easier way to accomplish the same.

This question is closely related to a question I posted yesterday. Sort of a second part.

user538578964
  • 723
  • 9
  • 25

0 Answers0