Specification Pattern and Boolean Operator Precedence

Posted by Anders Nielsen on Stack Overflow See other posts from Stack Overflow or by Anders Nielsen
Published on 2010-04-14T12:28:44Z Indexed on 2010/04/14 12:43 UTC
Read the original article Hit count: 415

In our project, we have implemented the Specification Pattern with boolean operators (see DDD p 274), like so:

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

Which permits a nice expressiveness of the rules using method-chaining, but it doesn't support the standard operator precedence rules of 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 rule isNiceCar2 is not satisfied if the car is not a convertible, which can be confusing since if they were booleans

isRed && isConvertible || isFerrari
would be equivalent to
isFerrari || isRed && isConvertible

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

The best solution we can come up with, is to outlaw the method-chaining, and use constructors instead:

OR(isFerrari, AND(isConvertible, isRed))

Does anyone have a better suggestion?

© Stack Overflow or respective owner

Related posts about specification-pattern

Related posts about specification