W przypadku tego rodzaju problemów Martin Fowler zaproponował wzór specyfikacji :
... wzorzec projektowy, w którym reguły biznesowe można łączyć, łącząc reguły biznesowe razem za pomocą logiki logicznej.
Wzorzec specyfikacji określa regułę biznesową, którą można łączyć z innymi regułami biznesowymi. W tym wzorcu jednostka logiki biznesowej dziedziczy swoją funkcjonalność po abstrakcyjnej klasie zagregowanej specyfikacji złożonej. Klasa Composite Specification ma jedną funkcję o nazwie IsSatisfiedBy, która zwraca wartość logiczną. Po utworzeniu instancji specyfikacja jest „łączona” z innymi specyfikacjami, dzięki czemu nowe specyfikacje są łatwe w utrzymaniu, a jednocześnie można je w dużym stopniu dostosować do własnych potrzeb. Ponadto po utworzeniu instancji logika biznesowa może, poprzez wywołanie metody lub odwrócenie kontroli, zmienić swój stan, aby stać się delegatem innych klas, takich jak repozytorium trwałości ...
Powyżej brzmi to trochę wysoko (przynajmniej dla mnie), ale kiedy wypróbowałem to w moim kodzie, poszło dość gładko i okazało się łatwe do wdrożenia i odczytu.
Moim zdaniem, główną ideą jest „wyodrębnienie” kodu, który wykonuje kontrole w dedykowanych metodach / obiektach.
W twoim netWorth
przykładzie może to wyglądać następująco:
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;
}
Twoja sprawa wydaje się dość prosta, aby wszystkie kontrole wyglądały OK, aby zmieścić się na prostej liście w ramach jednej metody. Często muszę podzielić się na więcej metod, aby poprawić czytanie.
Zazwyczaj grupuję / wyodrębniam metody związane ze „specyfikacją” w obiekcie dedykowanym, choć bez tego twoja sprawa wygląda dobrze.
// ...
Specification s, *spec = initialize(s, person);
if (spec->isSatisfied()) {
return person->assets - person->liabilities;
}
log("person doesn't satisfy spec");
return -1;
// ...
To pytanie w Stack Overflow zaleca kilka linków oprócz jednego wspomnianego powyżej:
Przykład wzorca specyfikacji . W szczególności odpowiedzi sugerują Dimecastsa „Nauka wzorca specyfikacji” jako przewodnik po przykładzie i wspominają o dokumencie „Specyfikacje” autorstwa Erica Evansa i Martina Fowlera .