Come garantire gli invarianti / la logica interna nei metodi setter

3

Secondo i principi del DDD, utilizzo metodi di fabbrica per creare oggetti coerenti e assicurare che gli oggetti siano nello stato giusto.

Ora sono in dubbio sulla logica interna dei metodi setter. Sono legato a un oggetto, simile al seguente frammento di codice, quindi prendiamolo come esempio:

public class UserCredentials {

    private String username;

    private UserCredentials() {
        super();
    }

    public static UserCredentials create (final String username) {
        String username = username.toUpperCase();
        UserCredentials newInstance = new UserCredentials(username);
        return newInstance;
    }

    private UserCredentials(final String username) {
        this.username = username;
    }

    public String getUsername() {
        return this.username;
    }

    public void setUsername(final String username) {
        this.username = username;
    }

    public void checkConsitency() {
        ...
        isUppercase();
        ...
    }
}

Abbiamo un invariante: il nome utente delle credenziali deve essere sempre in maiuscolo. Ora voglio assicurarmi che cambiare il nome utente non violi l'invariante.

Ma come posso garantire la regola?

  1. Riscrivo il metodo setter e aggiungo la logica di conversione al setter. Inconveniente: il setter contiene la logica.

  2. Mi affido ai client, che forniscono sempre il nome utente in maiuscolo e pubblicherò eccezioni di coerenza in caso di violazione. Svantaggio: l'origine dell'uso sbagliato è difficile da scoprire, oltretutto la sua cattiva pratica.

  3. Rimuovo il metodo setter e lo sostituisco con un metodo di dominio come changeUsername(String username) che contiene la logica di conversione. Inconveniente: gli sviluppatori esterni possono perdere il metodo setter.

A causa dell'affermazione "il nome utente delle credenziali deve sempre essere maiuscolo" tendo a preferire l'alternativa 3.

Ma esiste una soluzione più intelligente?

    
posta shylynx 08.04.2014 - 10:02
fonte

1 risposta

5

Scegli la soluzione # 1. Non c'è niente di sbagliato nei setter che contengono la convalida o la logica della coercizione. In effetti, questo è l'unico motivo per cui useremo setter e getter invece dei campi dei membri pubblici!

Anche il tuo metodo create factory è un po 'imbarazzante, in quanto non vi è alcun motivo per non utilizzare invece il costruttore:

public class UserCredentials {

    private String username;

    public UserCredentials(final String username) {
        super();
        this.username = coerceUsername(username);
    }

    public String getUsername() {
        return this.username;
    }

    public void setUsername(final String username) {
        this.username = coerceUsername(username);
    }

    private static String coerceUsername(final String username) {
        return username.toUpperCase();
    }
}
    
risposta data 08.04.2014 - 11:28
fonte