I costruttori di oggetti valore non funzionano, anche quando gli invarianti di classe lo prescrivono?

2

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?

    
posta user2180613 24.10.2016 - 19:48
fonte

1 risposta

3

Can anyone explain why constructors must not do work?

Perché i costruttori dispongono di meccanismi limitati per gestire i casi di errore. hai bisogno di per restituire un oggetto di quel tipo o lanciare un'eccezione. Non puoi restituire un tipo diverso. Non puoi segnalare il fallimento. Non puoi restituire nulla. Tu (quasi sempre) devi solo lanciare un'eccezione, in modo che i tuoi chiamanti si occupino di esso.

But then what about (Value)objects that explicitly embody some kind of computation result?

Se questi calcoli sono ragionevolmente veloci e falliscono solo in scenari eccezionali, allora è scusabile. A volte, implicitamente, questi calcoli rendono il codice più pulito imponendo quelle invarianti duri tramite un'interfaccia semplificata.

Ma come linea guida generale - i costruttori non dovrebbero lavorare.

Should that computation result always be processed in a factory instead, and only then be passed to the value object? Doesn't that fail to maintain the object's integrity constraints?

Sempre è probabilmente troppo strong, ma sì, generalmente dovrebbero. In alcune lingue è possibile fornire una funzione statica per creare l'oggetto che utilizza un costruttore privato. Ciò mantiene invariata l'oggetto mentre consente di gestire le condizioni di errore in modo più agevole.

    
risposta data 24.10.2016 - 19:59
fonte

Leggi altre domande sui tag