BOM template and boolean operator precedence

In our project, we implemented a BOM template with boolean operators (see DDD p 274), for example:

public abstract class Rule {

    public Rule and (Rule rule) {
        return new AndRule (this, rule);
    }

    public Rule or (Rule rule) {
        return new OrRule (this, rule);
    }

    public Rule not () {
        return new NotRule (this);
    }


    public abstract boolean isSatisfied (T obj);
}


class AndRule extends Rule {

    private Rule one;
    private Rule two;

    AndRule (Rule one, Rule two) {
        this.one = one;
        this.two = two;
    }

    public boolean isSatisfied (T obj) {
        return one.isSatisfied (obj) && two.isSatisfied (obj);
    }
}

class OrRule extends Rule {

    private Rule one;
    private Rule two;

    OrRule (Rule one, Rule two) {
        this.one = one;
        this.two = two;
    }

    public boolean isSatisfied (T obj) {
        return one.isSatisfied (obj) || two.isSatisfied (obj);
    }
}

class NotRule extends Rule {

    private Rule rule;

    NotRule (Rule obj) {
        this.rule = obj;
    }

    public boolean isSatisfied (T obj) {
        return! rule.isSatisfied (obj);                
    }
}

This allows you to express rules well using the chaining method, but does not support the standard operator precedence rules, which can lead to subtle errors.

The following rules are not equivalent:

Rule <Car> isNiceCar = isRed.and (isConvertible) .or (isFerrari);
Rule <Car> isNiceCar2 = isFerrari.or (isRed) .and (isConvertible);

The isNiceCar2 rule fails if the car is not convertible, which can be confusing as if they were boolean

isRed && isConvertible || isFerrari
, will be equivalent to
isFerrari || isRed && isConvertible

I understand that they would be equivalent if we rewrote isNiceCar2 as isFerrari.or (isRed.and (isConvertible)), but they are both syntactically correct.

The best solution we can think of is to disallow method chaining and use constructors instead:

OR (isFerrari, AND (isConvertible, isRed))

Does anyone have a better suggestion?

+2


a source to share


1 answer


Your "constructor" solution sounds right (at least semantically) as it forces you to build something closer to an expression tree than a chaining. Another solution would be to take the scoring functionality out of the Rule implementations, so the precedence can be enforced (walking the chain).



+2


a source







All Articles