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

发布于 2024-08-29 01:03:27 字数 1783 浏览 2 评论 0原文

在我们的项目中,我们使用布尔运算符实现了规范模式(参见 DDD p 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
would be equivalent to
isFerrari || isRed && isConvertible

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

我们能想到的最好的解决方案是禁止方法链接,并使用构造函数来代替:

OR(isFerrari, AND(isConvertible, isRed))

有人有更好的建议吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

面如桃花 2024-09-05 01:03:27

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

Your "constructor" solution sounds about right (semantically at least), in that it forces building something closer to an expression tree than a chain. Another solution would be to pull the evaluation functionality out of the Rule implementations so precedence can be enforced (by walking the chain).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文