Para este tipo de questões, Martin Fowler propôs um padrão de especificação :
... padrão de design, no qual as regras de negócios podem ser recombinadas, encadeando as regras de negócios usando a lógica booleana.
Um padrão de especificação descreve uma regra de negócios que pode ser combinada com outras regras de negócios. Nesse padrão, uma unidade de lógica de negócios herda sua funcionalidade da classe agregada abstrata Composite Specification. A classe Composite Specification possui uma função chamada IsSatisfiedBy que retorna um valor booleano. Após a instanciação, a especificação é "encadeada" com outras especificações, tornando as novas especificações fáceis de manter, mas com lógica de negócios altamente personalizável. Além disso, por instanciação, a lógica de negócios pode, por meio de invocação de método ou inversão de controle, ter seu estado alterado para se tornar um delegado de outras classes, como um repositório de persistência ...
Acima parece um pouco exagerado (pelo menos para mim), mas quando eu tentei no meu código, ele foi bem tranquilo e ficou fácil de implementar e ler.
Na minha opinião, a idéia principal é "extrair" o código que faz as verificações nos métodos / objetos dedicados.
Com o seu netWorth
exemplo, isso pode ter a seguinte aparência:
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;
}
Seu caso parece bastante simples, de modo que todas as verificações parecem OK para caber em uma lista simples em um único método. Muitas vezes, tenho que dividir para mais métodos para torná-lo melhor.
Eu também geralmente agrupo / extraio métodos relacionados "spec" em um objeto dedicado, embora seu caso pareça bom sem isso.
// ...
Specification s, *spec = initialize(s, person);
if (spec->isSatisfied()) {
return person->assets - person->liabilities;
}
log("person doesn't satisfy spec");
return -1;
// ...
Esta pergunta no Stack Overflow recomenda alguns links além do mencionado acima:
Exemplo de padrão de especificação . Em particular, as respostas sugerem o Dimecasts 'Learning the Specification pattern' para uma explicação passo a passo de um exemplo e mencionam o artigo "Specifications", de autoria de Eric Evans e Martin Fowler .