2 Stimmen

Spezifikationsmuster und Vorrang boolescher Operatoren

In unserem Projekt haben wir das Specification Pattern mit booleschen Operatoren implementiert (siehe DDD S. 274), und zwar 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);                
    }
}

Das erlaubt eine schöne Ausdruckskraft der Regeln unter Verwendung der Methodenverkettung, aber es unterstützt nicht die Standard-Operator-Präzedenzregeln, von denen man zu subtilen Fehlern führen können.

Die folgenden Regeln sind nicht gleichwertig:

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

Die Regel isNiceCar2 nicht erfüllt ist, wenn das Auto kein Cabrio ist, was verwirrend sein kann, denn wenn es sich um Boolesche

isRed && isConvertible || isFerrariwäre gleichbedeutend mit    isFerrari || isRed && isConvertible

Ich weiß, dass sie gleichwertig wären, wenn wir isNiceCar2 in isFerrari.or(isRed.and(isConvertible)) umschreiben würden, aber beide sind syntaktisch korrekt.

Die beste Lösung, die uns einfällt, ist, die Methodenverkettung zu verbieten und stattdessen Konstruktoren zu verwenden:

OR(isFerrari, AND(isConvertible, isRed))

Hat jemand einen besseren Vorschlag?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X