Come posso determinare se un campo debba essere separato nella sua classe?

4

Ad esempio, diciamo che ho questa classe:

public class Account {
    private String username
    private String email
    private String phoneNumber
    private String zipCode
    private String website
}

Ognuno di questi campi potrebbe potenzialmente essere separato nella propria classe:

public class Account {
    private Username username
    private Email email
    private PhoneNumber phoneNumber
    private ZipCode zipCode
    private Url website
}

public class Username {
    ...
}

public class Email {
    ...
}

public class PhoneNumber {
    ...
}

public class ZipCode {
    ...
}

public class Url {
    ...
}

Questa è considerata una buona pratica? C'è una regola empirica che posso usare per determinare se un campo debba essere separato nella sua classe?

    
posta StackOverflower 25.02.2018 - 03:35
fonte

5 risposte

7

Ritengo che una buona pratica fornisca una cosa: quegli oggetti dovrebbero avere metodi utili in loro, e getter e setter non contano. Il codice di convalida sarebbe.

L'ossessione primitiva è il nome dell'odore che stai evitando facendo questo. Se la validazione ha senso, perché alcuni valori non avrebbero senso, allora il campo potrebbe probabilmente essere giustificato come un tipo. Si crea la classe per simulare il tipo. Inoltre, questo aiuta la coesione offrendoti un posto dove tirare la logica relativa al campo insieme in un unico posto.

    
risposta data 25.02.2018 - 04:46
fonte
4

Abbiamo bisogno di buone astrazioni. Tuttavia, a volte non ha molto senso fornire astrazioni che non hanno un'utilità speciale. Quindi, è un compromesso da fare. Se devi sbagliare, fallo sul lato della creazione del tipo specifico del dominio per un dato semplice come int o string.

Considero generalmente accettabile includere tipi di date primitivi all'interno di un'altra astrazione (come il tuo Account), in quanto tali campi in tale contenitore forniscono il contesto / significato per questi tipi. BirthDate o AccountStartDate sono esempi, che ritengo siano sufficienti come date semplici; il loro significato è nel contesto del tipo di contenuto. Il raggruppamento di questi tipi aggiuntivi qui non offre necessariamente un valore e può rendere i valori più difficili da utilizzare.

Tuttavia, i tipi di numeri e i tipi di stringhe sono così comuni (e di basso livello) che possono essere molto inclini all'utilizzo, quindi merita un'attenzione aggiuntiva, ad es. essere avvolti in tipi significativi di dominio. Non va bene trovare questi tipi / attributi primitivi da soli al di fuori di alcune astrazioni contenenti. Quindi, se vedi che il valore di un campo primitivo è ampiamente condiviso nel codice, separato da un oggetto contenitore, allora è un odore che dovrebbero avere i loro tipi.

Nella direzione opposta, come per la data di nascita, può essere eccessivo assegnare a ciascun campo specifico un tipo specifico. Per un altro esempio, c'è una nozione di numero di telefono per un contatto di emergenza. Comporre questo numero equivale a comporre qualsiasi altro numero, quindi non vogliamo o non abbiamo bisogno di classi speciali per comporre un numero di telefono di emergenza, e semplicemente sappiamo che è il contatto di emergenza dall'astrazione contenente dal campo piuttosto che dal tipo .

    
risposta data 25.02.2018 - 06:53
fonte
2

Nella maggior parte dei casi è buona norma separare questi campi nelle classi. OOP è tuo amico:).

Darò un esempio. Probabilmente, il tuo e-mail è un campo che può apparire in molti punti della tua applicazione. Lavorando solo con la posta elettronica come campo è necessario disporre di una sorta di classe Helper / Util con metodi statici per eseguire alcune convalide / azioni di posta elettronica in ogni posizione in cui viene visualizzato il campo. Questo non è molto riutilizzabile ed è fastidioso, perché qualcuno può dimenticare di usare l'Helper / Util o addirittura dimenticare di chiamare qualche metodo importante all'interno di Helper / Util per eseguire un'azione su e-mail .

Creazione di una classe Email , è molto più semplice riutilizzare le azioni di posta elettronica:

class Email {
    public String validate();
    public String getDomain();
    public String getValue();
    public String getValueForPublicWeb(); // return john at gmail dot com
}

E puoi usare in qualsiasi classe molto facilmente:

class Person {
    private Email email;
}

class Login {
    private Email email;
}
    
risposta data 25.02.2018 - 13:41
fonte
1

Sì, è una buona pratica.

Considerando che le "classi stupide" sono classi con costruttore predefinito e solo getter e setter di metodi che non eseguono alcuna regola aziendale.

È un buon approccio quando non si usano classi stupide, si separano le responsabilità del proprio codice per ogni classe che dovrebbe interessarsi ai suoi dati. Le tue lezioni saranno molto coese. Potresti aumentare l'accoppiamento.

// a class that isn't dumb.
public class Username {
    private String username;
    public Username(String username){
        this.validateUsername(username);
        this.username = username;            
    }
    public setName(String username){
        this.validateUsername(username);
        this.username = username;
    }
    public String getName(){
        return this.username;
    }
    private validateUsername(String username){
        if(username == null){
            throw new UsernameShouldNotBeNullException();
        }
        if(username.length() <= 4){
            throw new UsernameShouldNotHaveLessThanFourLenghtException();
        }
    }
}

In questo modo, stai concentrando la regola aziendale su Username nella classe Username. Non diffonderete le regole relative al nome utente da parte dell'intero sistema. Nessun servizio saprà come istanziare un nome utente valido, solo la classe Username.

    
risposta data 19.03.2018 - 21:12
fonte
0

La relazione tra Account e WebSite / PhoneNumbers / Dati è pertinente e dipende dal modello di dati effettivo.

Presupposto "L'account non ha bisogno di conoscere i dettagli dei componenti del numero di telefono (o di altri dati): Questo sarebbe se Account avesse bisogno solo di numeri telefonici o di siti web generici, e che l'imballaggio del magazzino avesse altrettanto bisogno di numeri di telefono generici e di siti web. Ma anche i numeri di telefono o siti web hanno alcuni problemi di convalida specifici, a mio parere. In questo modello, Account ha solo "ha un" "PhoneNumber" e la classe PhoneNumber può essere gestita autonomamente e rilasciata indipendentemente se le firme dei metodi di accesso non cambiano.

Supponendo che l'account abbia effettivamente un utilizzo specifico per account per dati apparentemente primitivi: Potrebbe essere che gli account abbiano davvero metodi di gestione dei dati specifici per l'account che non possono essere condivisi con l'imballaggio del magazzino. Quindi disponi di moduli di dati solo per l'account definiti con l'account di classe. Puoi ricavare varianti specifiche per l'account di classe Web o classe phonenumber, ma sembra troppo lavoro.

    
risposta data 25.02.2018 - 13:25
fonte

Leggi altre domande sui tag