2014-09-12 9 views
8

Ho problemi nell'organizzazione del mio codice quando voglio aggiornare un oggetto dominio non semplice. Il problema è separare le responsabilità per il controller e il livello di servizio.Grails: l'uso del livello di servizio

In modo più esplicito, si supponga di disporre di un client di classe dominio che dipende da altre classi di dominio come Indirizzo e così via.

Nella vista è presente un gsp per modificare alcune proprietà dei client, incluse alcune delle proprietà nidificate come street sull'indirizzo.

Quando desidero aggiornare questi campi, chiamo il metodo di aggiornamento su un Controller (in questo caso il ClientController).

Mi piace la funzione proveniente dagli errori di una classe di dominio quando convalidata. Come se nel Controller scrivere

Client client = Client.get(params.id) 
client.properties = params 
client.validate() 

Se il cliente ha ora errori è molto facile per visualizzarli nella vista edit.

Ma, ho pensato che l'aggiornamento, il salvataggio e il recupero del client dal database (Client.get (theId)) dovrebbero essere gestiti dal livello di servizio. Nel mio caso devo aggiornare o creare altri oggetti di dominio (come l'indirizzo) prima di aggiornare il client.

Quindi una delle mie domande è come dovrebbe apparire l'API per il livello di servizio?

public ... updateClient(…) 

Nella letteratura hanno il banale esempio di aggiornamento dell'età di una persona. Quindi, la loro API è costituita dall'ID della persona e dalla nuova era. Ma, nel mio caso, ho una decina di parametri dalla vista e sono solo un sottoinsieme di tutte le proprietà di un client e non so quale di questi sia cambiato.

  1. Mi piacerebbe avere un client nel controller che possa convalidare e inviare nuovamente alla vista di modifica se ha errori di convalida.
  2. Vorrei gestire le interazioni e le transazioni del database dal livello di servizio.

Come posso combinare questi? Quali responsabilità dovrebbero avere i diversi livelli per quanto riguarda l'aggiornamento? Come dovrebbe apparire l'API del livello di servizio per quanto riguarda l'aggiornamento?

Se esiste una buona implementazione di riferimento, sarei felice di studiarla. Molte volte il livello di servizio è sfortunatamente totalmente o parzialmente ignorato.

+1

+1 una domanda ben scritta. – David

risposta

5

Il pezzo mancante di questo puzzle è command objects. Queste classi rappresentano il contratto per la tua API nei tuoi servizi e ti offrono la possibilità di avere una lezione concreta per le tue opinioni e per la convalida. Diamo un'occhiata a un esempio.

Data una classe di dominio di Client quali ad Address e diversi Phone casi il vostro livello di servizio potrebbe essere simile a questo:

... 
class ClientService { 
    def updateClient(ClientUpdateCommand cmd) { 
    .. 
    } 
} 
... 

Mentre il ClientUpdateCommand simile a questa:

@grails.validation.Validateable 
class ClientUpdateCommand { 
    Long id 
    String name 
    List<PhoneUpdateCommand> phoneNumbers = [] 
    AddressUpdateCommand address = new AddressUpdateCommand() 
    ... 
    static constraints { 
    id(nullable: false) 
    name(nullable: false, blank: false, size:1..50) 
    ... 
    } 
    ... 
} 

Avrete si noti che questo oggetto comando è composto da altri oggetti comando e ha vincoli per la convalida. Potrebbe sembrare che tu stia replicando le tue classi di dominio qui, ma ho scoperto che più la tua applicazione è complessa, più differenze appariranno tra le classi di dominio e gli oggetti di comando.

Il prossimo è l'utilizzo dell'oggetto comando all'interno del controller e delle visualizzazioni. Un metodo di controllo può essere simile a questa:

Class ClientController { 
    ... 
    def clientService 
    ... 
    def edit(ClientUpdateCommand cmd) { 
    ... 
    cmd = clientService.load(cmd.id) 
    Map model = [client: cmd] 
    render(view: 'edit', model: model) 
    } 
    def update(ClientUpdateCommand cmd) { 
    Map model = [client: cmd] 
    if (cmd.hasErrors() { 
     render(view: 'edit', model: model] 
     return 
    } else { 
     clientService.update(cmd) 
     ... 
    } 
    ... 
    } 
} 

ho lasciato un sacco fuori del controller come io non volevo annoiarvi con i dettagli, ma piuttosto di mostrare come un oggetto di comando sostituisce l'istanza dominio. In un certo senso è un po 'più di lavoro, ma ti allontana completamente dalla manipolazione delle classi di dominio e la delega al servizio che hai creato. Noterai inoltre che l'oggetto comando sostituisce l'istanza della classe dominio per il tuo modello per le tue viste. Non mi preoccuperò di fornirti alcun esempio di GSP, dato che in realtà non cambiano molto quando si usano oggetti di comando come questo.

Sono sicuro che potrebbero esserci interi capitoli di libri scritti sull'argomento, ma si spera che questo ti dia qualche informazione e puoi vedere che la risposta alle tue domande è: Oggetti di comando.

+2

+1 spot on. Ben fatto non menzionare le classi di dominio possono essere utilizzate anche come oggetti di comando. Sebbene ciò sia possibile, l'uso di oggetto comando separa tale preoccupazione. – dmahapatro

Problemi correlati