Für diese Art von Fragen schlug Martin Fowler das Spezifikationsmuster vor :
... Entwurfsmuster, bei dem Geschäftsregeln durch Verketten der Geschäftsregeln mithilfe der Booleschen Logik neu kombiniert werden können.
Ein Spezifikationsmuster beschreibt eine Geschäftsregel, die mit anderen Geschäftsregeln kombiniert werden kann. In diesem Muster erbt eine Business-Logik-Einheit ihre Funktionalität von der abstrakten aggregierten Klasse Composite Specification. Die Composite Specification-Klasse verfügt über eine Funktion namens IsSatisfiedBy, die einen booleschen Wert zurückgibt. Nach der Instantiierung wird die Spezifikation mit anderen Spezifikationen "verkettet", wodurch neue Spezifikationen leicht zu pflegen und dennoch in hohem Maße anpassbar sind. Darüber hinaus kann der Status der Geschäftslogik durch Methodenaufruf oder Umkehrung der Steuerung geändert werden, um ein Delegat anderer Klassen wie z. B. eines Persistenz-Repositorys zu werden.
Oben klingt ein bisschen hochnäsig (zumindest für mich), aber als ich es in meinem Code ausprobierte, lief es ziemlich reibungslos und erwies sich als einfach zu implementieren und zu lesen.
Nach meiner Auffassung besteht die Hauptidee darin, Code zu "extrahieren", der die Prüfungen in dedizierten Methoden / Objekten durchführt.
In Ihrem netWorth
Beispiel könnte dies folgendermaßen aussehen:
int netWorth(Person* person) {
if (isSatisfiedBySpec(person)) {
return person->assets - person->liabilities;
}
log("person doesn't satisfy spec");
return -1;
}
#define BOOLEAN int // assuming C here
BOOLEAN isSatisfiedBySpec(Person* person) {
return Person != NULL
&& person->isAlive
&& person->assets != -1
&& person->liabilities != -1;
}
Ihr Fall scheint ziemlich einfach zu sein, sodass alle Überprüfungen so aussehen, dass sie in eine einfache Liste innerhalb einer einzelnen Methode passen. Ich muss oft auf mehrere Methoden aufteilen, um das Lesen zu verbessern.
Normalerweise gruppiere / extrahiere ich auch "spec" -bezogene Methoden in einem dedizierten Objekt, obwohl Ihr Fall ohne das in Ordnung aussieht.
// ...
Specification s, *spec = initialize(s, person);
if (spec->isSatisfied()) {
return person->assets - person->liabilities;
}
log("person doesn't satisfy spec");
return -1;
// ...
Diese Frage bei Stack Overflow empfiehlt einige Links zusätzlich zu den oben genannten:
Spezifikationsmuster-Beispiel . Insbesondere schlagen die Antworten Dimecasts 'Learning the Specification pattern' für eine exemplarische Darstellung eines Beispiels vor und erwähnen das von Eric Evans und Martin Fowler verfasste "Specifications" -Papier .