Usa le interfacce getter come modo per riutilizzare i campi DTO

0

Supponiamo di avere un sacco di DTO per uno stesso modello di dominio come questo:

class User{}
//DTO
@Value.Immutable
interface SimpleUserDTO {
        getName
        getAge
}
@Value.Immutable
interface RegisterUserDTO {
        getName
        getPassword
        getAge
        getAvatar
}
@Value.Immutable
interface ChangeUserPasswordDTO {
        getName
        getPassword
        getNewPassword
}

Ha senso creare interfacce separate e riutilizzarle in DTO:

interface Name{ getName }
interface Age{ getAge }
interface Password{ getPassword }

@Value.Immutable
interface SimpleUserDTO extends
        Name,
        Age
@Value.Immutable
interface RegisterUserDTO extends
        Name,
        Password,
        Age,
        Avatar,
@Value.Immutable
interface ChangeUserPasswordDTO extends
        Name,
        Password,
        NewPassword

In questo modo, posso ottenere due cose:

  • Ogni DTO avrà sempre la stessa firma di campo, ad esempio: Name avrà sempre String getName() , evitando errori
  • Centralizza annotazione, evita la duplicazione
  • Più facile da distinguere tra diversi campi da DTO diversi, quindi getName da ChangeUserPasswordDTO è uguale a getName da RegisterUserDTO poiché entrambi estendono lo stesso Name ma diversi da getName da BlogDTO
posta cdxf 08.05.2018 - 11:28
fonte

2 risposte

3

La considerazione principale qui è il principio di segregazione intefrace

The interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use. ISP splits interfaces that are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them.

Per maggiore chiarezza, diamo un'occhiata a un altro esempio (scusa la sintassi C #).

public interface IManageUserService()
{
    void SaveUser();
    void DeleteUser();
}

Queste interfacce dovrebbero essere divise in ISaveUserService e IDeleteUserService ?

La risposta a ciò si basa sulla possibilità per una classe di implementare una e non l'altra . Se la tua logica aziendale richiede un servizio per implementare entrambi (o nessuno dei due), allora dovrebbero stare insieme. Se è perfettamente possibile per un servizio eseguire solo una delle attività, è necessario separarle.

Tornando al tuo esempio, possiamo porre la stessa domanda qui:

Ci possono essere classi che hanno solo Name o un Age , ma non entrambe?

Supporrei di sì. Ciò significa che è davvero corretto dividere le interfacce.

Footnote
There is, however, an argument of reasonability. If it's technically possible to use only part of an interface, but it doesn't actually ever occur in practice; then it might be better to keep the interface together in favor of writing less boilerplate code.

In such a case, you need to consider the likelihood that you will have to split the interface in the future (if an object is developed which does only use half of the interface). If the odds are low, then it's fair to avoid unnecessarily splitting the interface. If the odds are high, you're better off doing it now instead of having to refactor it later.

Dividere l'interfaccia in sub-interfacce

Potremmo raggiungere un punto in cui tentare di suddividere gli atomi qui. Hai intenzione di creare un'interfaccia per ogni proprietà esistente? Perché è un sacco di lavoro, il che non offre alcun vantaggio diretto per quanto posso vedere.

  1. Every DTO will always have the same field signature, for example: Name will always have String getName(), avoiding mistakes

Tecnicamente corretto, ma non vale la pena di creare interfacce per ogni proprietà. A mio parere.

A parte il completamento dell'intelligenza e il controllo ortografico in fase di compilazione, esiste una ragione logica per fare ciò?

  1. Centralize Annotation, avoid duplication

Questo sembra lo stesso argomento del precedente punto elenco.

3.1. Easier to distinguish different fields from differnt DTOs, so getName from ChangeUserPasswordDTO is the same as getName from RegisterUserDTO since they both extends the same Name

Se non ci sono relazioni tra Foo.Name e Bar.Name , c'è davvero qualcosa da guadagnare dall'avere Foo e Bar implementare la stessa interfaccia IName ?

Non sono convinto che stai guadagnando nulla che superi lo sforzo di renderlo tale. L'unico vantaggio di avere un'interfaccia è garantire un contratto tra diverse classi che implementano la stessa interfaccia. Perché mai sarà rilevante per FooDto e BarDto per essere indirizzati in modo intercambiabile (cioè come una variabile di tipo IName )?

3.2. but different from getName from BlogDTO

Sono un po 'in difficoltà qui; ma questo può essere specifico della lingua. Manca questo dal tuo codice di esempio?

Pensavo che il tuo obiettivo fosse utilizzare la stessa interfaccia per ogni classe (dto) che ha una proprietà Name ? Perché BlogDTO dovrebbe essere diverso da allora?

    
risposta data 08.05.2018 - 13:26
fonte
4

Nel contesto dello sviluppo orientato agli oggetti, nessuna delle due opzioni è corretta. Per una risposta breve però: potresti provare a creare DTO che includono l'un l'altro, nel qual caso non dovrai duplicare materiale.

Ritorno a OO: le interfacce e le astrazioni dovrebbero essere utilizzate su funzioni aziendali e non dati . Pertanto, la creazione di un'interfaccia per i dati o l'utilizzo di DTO in primo luogo è di solito un segno di design non-oo.

Se vuoi risolvere questo problema prova a modellare funzionalità : cambia password, registra, mostraAvatar, cose del genere.

    
risposta data 08.05.2018 - 11:42
fonte

Leggi altre domande sui tag