规范模式和布尔运算符优先级

时间:2010-04-14 12:28:44

标签: operator-precedence specifications specification-pattern

在我们的项目中,我们使用布尔运算符实现了规范模式(参见DDD第274页),如下所示:

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

使用方法链接可以很好地表达规则,但它不支持标准的运算符优先级规则 导致微妙的错误。

以下规则不相同:

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

如果汽车不是敞篷汽车,那么规则 isNiceCar2 就不满意了,因为如果它们是布尔值,这可能会让人感到困惑

isRed && isConvertible || isFerrari
等同于{{2} }

我意识到如果我们将isNiceCar2重写为isFerrari.or(isRed.and(isConvertible)),它们将是等价的,但两者在语法上都是正确的。

我们可以提出的最佳解决方案是取消方法链,并改为使用构造函数:

isFerrari || isRed && isConvertible

有人有更好的建议吗?

1 个答案:

答案 0 :(得分:2)

你的“构造函数”解决方案听起来是正确的(至少在语义上),因为它强制构建更接近表达式树而不是链的东西。另一个解决方案是将评估功能从规则实现中拉出来,这样就可以强制执行优先级(通过遍历链)。