Para estos temas amables Martin Fowler propuso especificación del patrón :
... patrón de diseño, mediante el cual las reglas de negocio pueden recombinarse encadenando las reglas de negocio juntas usando lógica booleana.
Un patrón de especificación describe una regla comercial que se puede combinar con otras reglas comerciales. En este patrón, una unidad de lógica de negocios hereda su funcionalidad de la clase de Especificación compuesta agregada abstracta. La clase de especificación compuesta tiene una función llamada IsSatisfiedBy que devuelve un valor booleano. Después de la creación de instancias, la especificación se "encadena" con otras especificaciones, lo que hace que las nuevas especificaciones sean fáciles de mantener, pero con una lógica empresarial altamente personalizable. Además, tras la creación de instancias, la lógica de negocios puede, a través de la invocación de métodos o la inversión de control, alterar su estado para convertirse en un delegado de otras clases, como un repositorio de persistencia ...
Lo anterior suena un poco alto (al menos para mí), pero cuando lo probé en mi código, fue bastante sencillo y resultó fácil de implementar y leer.
A mi modo de ver, la idea principal es "extraer" el código que realiza las comprobaciones en métodos u objetos dedicados.
Con su netWorthejemplo, esto podría verse de la siguiente manera:
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;
}
Su caso parece bastante simple para que todas las comprobaciones se vean bien y quepan en una lista simple dentro de un solo método. A menudo tengo que dividirme en más métodos para que se lea mejor.
También suelo agrupar / extraer métodos relacionados con "especificaciones" en un objeto dedicado, aunque su caso se ve bien sin eso.
// ...
Specification s, *spec = initialize(s, person);
if (spec->isSatisfied()) {
return person->assets - person->liabilities;
}
log("person doesn't satisfy spec");
return -1;
// ...
Esta pregunta en Stack Overflow recomienda algunos enlaces además de uno mencionado anteriormente:
Ejemplo de patrón de especificación . En particular, las respuestas sugieren Dimecasts 'Learning the Specification pattern' para un tutorial de un ejemplo y mencionan el documento "Especificaciones" escrito por Eric Evans y Martin Fowler .