Образец спецификации и приоритет логического оператора - PullRequest
2 голосов
/ 14 апреля 2010

В нашем проекте мы реализовали шаблон спецификаций с логическими операторами (см. 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
было бы эквивалентно
isFerrari || isRed && isConvertible

Я понимаю, что они были бы эквивалентны, если бы мы переписали isNiceCar2 в isFerrari.or (isRed.and (isConvertible)), но оба синтаксически верны.

Лучшее решение, которое мы можем найти, - запретить цепочку методов и использовать вместо нее конструкторы:

OR(isFerrari, AND(isConvertible, isRed))

У кого-нибудь есть лучшее предложение?

1 Ответ

2 голосов
/ 14 апреля 2010

Ваше «конструкторское» решение звучит как правильное (по крайней мере, семантически) в том смысле, что оно заставляет строить нечто ближе к дереву выражений, чем к цепочке. Другое решение состоит в том, чтобы извлечь функциональные возможности оценки из реализаций Правил, чтобы можно было обеспечить приоритет (обходя цепочку).

...