0

Background:

I have a JSON object (named JSONConditionObject) which looks like the following,

{
    "condition1":"value1",
    "condition2":"value2,value3 ..."
    //more fields below very likely to be added/changed
    //also the nature of values for a condition (String/List) might change as well
    //For eg, it can be another json itself
}

I want to read this JSON object -> validate the conditions and if all conditions are true, perform some task.

My Approach:

The best I could think of is the Decorator pattern to make the code extensible/flexible. Each field will be a decorator around a base object (base object will have logic to perform the final task if all conditions are true),

public abstract class ConditionDecorator extends Condition{

    private Condition condition; // Condition is the top level abstract class signifying a json condition

    @Override
    public void apply(Task task) {
        if(this.shouldApply(task)){
            condition.apply(task);
        }
    }
}

Then each condition in the JSONConditionObject will have its own class like so,

public class Condition1Context extends ConditionDecorator {

    private Condition condition;
    private String condition1;

    public Condition1Context(Condition condition, JSONConditionObject jsonConditionObject){
        super(condition);
        this.condition = condition;
        this.condition1 = jsonConditionObject.getCondition1();
    }

    @Override
    protected boolean shouldApply(Task task) {
        //will have logic for validating condition
        ...
    }

}

Finally, I read the JSONConditionObject and return a variable of type Condition which can be used to validate the conditions one after another. If a new condition is added in the future, I will just have to create a new class for it (like Condition1Context above) and decorate the final Condition object with it.

My Question:

This approach is a bit verbose and leads to generation of a lot of classes in my project (one single class for each condition). Would there be another way which is a bit more elegant and would require lesser code?

2
  • I don't get it: is the JSON-object the definition of the conditions (which are then applied to something else) or is it the object to be validated?
    – mtj
    Commented Jun 23, 2020 at 5:24
  • @mtj it is the definition of the conditions which are to be applied to something else
    – mettleap
    Commented Jun 23, 2020 at 5:36

3 Answers 3

1

Validating a dynamic list of conditions to perform some action is a typical use case for a rule engine.

A simple and effective approach is then to use the interpreter pattern for the conditions:

  • a basic condition is a TerminalExpression which can have several input parameters
  • any combination of condition, such as a list of conditions combined with an implicit AND, is then a NonTerminalExpression
  • the values that are to be used for the input parameters (when evaluating a condition) are held in a context.

This separation between context and condition-expression is very useful when the rules are loaded and then executed several times elsewhere, with different execution context each time.

In your case, the JSON will be the initial source for the evaluation context (i.e. values associated with the condition), and at the same time the main source for building the expression (i.e. which conditions to use) dynamically.

Since the rules itself already use values, you could simplify the design by keeping with the rules an initial context for the parameter values (configuration context), and an execution context when the conditions are applied to objects being validated.

A rule would be a pair: an Expression that evaluates a JSON condition and a an Action that is fired if the condition is true. Decoupling the actions from the condition evaluation is key to avoid a combinatorial explosion.

Alternatively, if you have only one dynamic rule and not a list of (potentially interacting) rules, you could very well use a base rule and decorators, but for varying the action, not the conditions.

0

The approach you describe, which basically is a dynamic configuration (JSON) which leads to a hard class structure, seems to generate a lot of ugly code.

You'd have to have some kind of registry to hold the various condition objects, and then create them via reflection (or even worse: through another layer of indirection) and finally somehow tack them together. (... and to lots of error handling on the way, as usual when you take the reflection route.)

As an alternative, I suggest you look into a ready-made business-rules framework. For java, drools (https://www.drools.org/) is well established, relatively easy to set up, and probably suited to your task.

0

When the conditions are not that complex you could use the specification pattern to map your conditions to classes, so having a class per primitive condition which you can combine with logical operations (Specification pattern). Maybe have a look at Java predicates/bipredicates. For generating your specification hierarchy from the JSON, you could write a simple interpreter.

Not the answer you're looking for? Browse other questions tagged or ask your own question.