Pour ce type de problème, Martin Fowler a proposé un modèle de spécification :
... modèle de conception, par lequel les règles métier peuvent être recombinées en enchaînant les règles métier en utilisant une logique booléenne.
Un modèle de spécification décrit une règle métier qui peut être combinée avec d'autres règles métier. Dans ce modèle, une unité de logique métier hérite ses fonctionnalités de la classe de spécification composite agrégée abstraite. La classe Spécification composite a une fonction appelée IsSatisfiedBy qui renvoie une valeur booléenne. Après l'instanciation, la spécification est "enchaînée" avec d'autres spécifications, ce qui rend la nouvelle logique métier facilement maintenable, mais hautement personnalisable. De plus, lors de l'instanciation, la logique métier peut, par invocation de méthode ou inversion de contrôle, voir son état modifié afin de devenir un délégué d'autres classes comme un référentiel de persistance ...
Les sons ci-dessus sont un peu élevés (du moins pour moi), mais quand je l'ai essayé dans mon code, cela s'est bien passé et s'est avéré facile à mettre en œuvre et à lire.
De mon point de vue, l'idée principale est d'extraire du code qui effectue les vérifications dans des méthodes / objets dédiés.
Avec votre netWorth
exemple, cela pourrait ressembler à ceci:
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;
}
Votre cas semble assez simple de sorte que toutes les vérifications semblent OK pour tenir dans une liste simple dans une seule méthode. Je dois souvent me séparer de plusieurs méthodes pour améliorer la lecture.
Je regroupe / extrait généralement des méthodes liées aux "spécifications" dans un objet dédié, bien que votre cas semble OK sans cela.
// ...
Specification s, *spec = initialize(s, person);
if (spec->isSatisfied()) {
return person->assets - person->liabilities;
}
log("person doesn't satisfy spec");
return -1;
// ...
Cette question sur Stack Overflow recommande quelques liens en plus de celui mentionné ci-dessus:
Exemple de modèle de spécification . En particulier, les réponses suggèrent Dimecasts «Learning the Specification pattern» pour une procédure pas à pas d'un exemple et mentionnent le document «Spécifications» rédigé par Eric Evans et Martin Fowler .