Per questo tipo di problemi Martin Fowler ha proposto il modello di specifica :
... modello di progettazione, in base al quale le regole aziendali possono essere ricombinate concatenando le regole aziendali utilizzando la logica booleana.
Un modello di specifica delinea una regola aziendale che è combinabile con altre regole aziendali. In questo modello, un'unità di business logic eredita la sua funzionalità dalla classe di aggregazione delle specifiche composite astratte. La classe Specifica composita ha una funzione chiamata IsSatisfiedBy che restituisce un valore booleano. Dopo l'istanza, la specifica viene "concatenata" con altre specifiche, rendendo le nuove specifiche facilmente gestibili, ma con una logica di business altamente personalizzabile. Inoltre, al momento dell'istanza, la logica aziendale può, attraverso l'invocazione del metodo o l'inversione del controllo, alterare il suo stato per diventare un delegato di altre classi come un repository di persistenza ...
Sopra suona un po 'troppo acuto (almeno per me), ma quando l'ho provato nel mio codice è andato abbastanza liscio e si è rivelato facile da implementare e leggere.
Per come la vedo io, l'idea principale è quella di "estrarre" il codice che esegue i controlli in metodi / oggetti dedicati.
Con il tuo netWorth
esempio, questo potrebbe apparire come segue:
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;
}
Il tuo caso appare piuttosto semplice in modo che tutti i controlli appaiano OK per rientrare in un semplice elenco all'interno di un singolo metodo. Spesso devo dividere in più metodi per farlo leggere meglio.
Inoltre in genere raggruppo / estraggo i metodi relativi alle "specifiche" in un oggetto dedicato, anche se il tuo caso sembra OK senza quello.
// ...
Specification s, *spec = initialize(s, person);
if (spec->isSatisfied()) {
return person->assets - person->liabilities;
}
log("person doesn't satisfy spec");
return -1;
// ...
Questa domanda su Stack Overflow consiglia alcuni collegamenti oltre a uno sopra menzionato:
Esempio di modello di specifica . In particolare, le risposte suggeriscono che Dimecasts "Impara il modello delle specifiche" per una panoramica di un esempio e menziona il documento "Specifiche" scritto da Eric Evans e Martin Fowler .