Oggi ho avuto una discussione con un collega.
Sono a conoscenza del fatto che una classe ha la responsabilità di garantire che i suoi oggetti abbiano uno stato valido quando interagiscono con al di fuori della classe. Il motivo di questa regola è che la classe non sa chi sono i suoi utenti e che dovrebbe fallire in modo prevedibile quando viene interagita in modo illegale. A mio avviso, questa regola si applica a tutte le classi, inclusi gli oggetti immutabili, in qualche modo primitivi, che fanno poco più che contenere i valori primitivi.
Nella situazione specifica in cui ho avuto una discussione odierna, il costruttore di un tale ValueObject doveva fare un po 'di lavoro (doveva chiamare un paio di getter) per acquisire i valori necessari per uno stato valido. La correlazione tra i risultati calcolati è una condizione degli invarianti di classe di ValueObject, vale a dire che devono avere la stessa fonte.
Questa è un'illustrazione della classe (esempio di codice php):
class Example {
private $someValue;
private $computedResultA;
private $computedResultB;
public function __construct($someValue, $someDependency) {
$this->someValue = $someValue;
$this->computedResultA = $someDependency->computeResultA();
$this->computedResultB = $someDependency->computeResultB();
}
}
Il mio collega sostiene che è meglio calcolare i risultati nella classe che crea un'istanza di ValueObject e passare questi risultati primitivi al costruttore di ValueObject. Dopotutto, ragiona, i costruttori non devono lavorare. Inoltre, il codice di test diventerebbe più grande se fosse necessario fornire un mock al costruttore di ValueObject - qualcosa che non è necessario quando vengono forniti semplicemente valori primitivi. E il codice apparentemente test è più importante del codice testato.
Questa è un'illustrazione del codice che preferisce:
class Example {
private $someValue;
private $computedResultA;
private $computedResultB;
public function __construct($someValue, $computedResultA, $computedResultB) {
$this->someValue = $someValue;
$this->computedResultA = $computedResultA;
$this->computedResultB = $computedResultB;
}
}
Qualcuno può spiegare perché i costruttori non devono lavorare? Google mi dice che i costruttori non dovrebbero causare effetti collaterali. Ma allora che dire (Valore) Oggetti che incorporano esplicitamente un tipo di risultato di calcolo? Questo risultato dovrebbe sempre essere elaborato in fabbrica, e solo dopo essere passato all'oggetto valore? Non è questo che non riesce a mantenere i vincoli di integrità dell'oggetto?