2014-09-12 29 views
8

Mam problemy z organizowaniem mojego kodu, gdy chcę zaktualizować obiekt domeny, który nie jest prosty. Problem polega na oddzieleniu odpowiedzialności za kontroler od warstwy usługowej.Grails - korzystanie z warstwy usługi

Załóżmy, że mamy klienta klasy domeny, który zależy od innych klas domen, takich jak Adres i tak dalej.

W widoku istnieje plik Gsp do edytowania niektórych właściwości klientów, w tym niektórych właściwości zagnieżdżonych, takich jak ulica na adresie.

Kiedy chcę zaktualizować te pola, nazywam metodę aktualizacji na kontrolerze (w tym przypadku ClientController).

Podoba mi się funkcja pochodząca z błędów klasy domeny po sprawdzeniu poprawności. Tak jak w przypadku kontrolera, należy napisać:

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

Jeśli klient ma teraz błędy, bardzo łatwo jest wyświetlić je w widoku edycji.

Ale, myślałem, że aktualizowanie, zapisywanie i pobieranie klienta z bazy danych (Client.get (theId)) powinno być obsługiwane przez warstwę usługi. W moim przypadku muszę zaktualizować lub utworzyć inne obiekty domeny (takie jak adres) przed aktualizacją klienta.

Jednym z moich pytań jest jak powinien wyglądać interfejs API dla warstwy usługi?

public ... updateClient(…) 

W literaturze mają banalny przykład aktualizacji wieku osoby. Ich interfejs API składa się z identyfikatora osoby i nowego wieku. Ale w moim przypadku mam około dziesięciu parametrów z widoku i są one tylko podzbiorem wszystkich właściwości klienta i nie wiem, który z nich się zmienił.

  1. Chciałbym mieć klienta w kontrolerze, który będę mógł zweryfikować i ponownie wysłać do widoku edycji, jeśli ma błędy sprawdzania poprawności.
  2. Chciałbym obsługiwać interakcje i transakcje bazy danych z warstwy usługi.

Jak mogę je połączyć? Jakie obowiązki powinny mieć poszczególne warstwy dotyczące aktualizacji? Jak powinien wyglądać interfejs API warstwy usługi dotyczący aktualizacji?

Jeśli istnieje dobra implementacja referencyjna, chętnie bym to uczył. Wiele razy warstwa usług jest niestety całkowicie lub częściowo ignorowana.

+1

+1 dobrze napisane pytanie. – David

Odpowiedz

5

Brakujący element tej układanki to command objects. Klasy te reprezentują kontrakt API dla twoich usług i dają ci możliwość posiadania konkretnej klasy dla twoich poglądów i dla walidacji. Spójrzmy na przykład.

Biorąc pod uwagę klasę domenową Client który jako Address i kilku Phone przypadkach Twój Warstwa usług może wyglądać następująco:

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

Choć ClientUpdateCommand wygląda mniej więcej tak:

@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) 
    ... 
    } 
    ... 
} 

Będziesz zauważ, że ten obiekt polecenia składa się z innych obiektów poleceń i ma ograniczenia do sprawdzania poprawności. Może się wydawać, że replikujesz tutaj swoje klasy domen, ale odkryłem, że im bardziej złożona jest twoja aplikacja, tym więcej różnic pojawi się między klasami domen a obiektami poleceń.

Następny jest użycie obiektu polecenia w kontrolerze i widokach. Metoda kontroler może wyglądać następująco:

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) 
     ... 
    } 
    ... 
    } 
} 

Mam pozostawia wiele z kontrolera jako że nie chcę was zanudzać szczegółami, ale raczej pokazują, jak przedmiot komenda zastępuje instancji domeny. W pewnym sensie jest to trochę więcej pracy, ale całkowicie odsuwa cię od manipulowania klasami domeny i deleguje to do usługi, którą utworzyłeś. Zauważysz także, że obiekt polecenia zastępuje instancję klasy domeny dla twojego modelu dla twoich widoków. Nie będę zawracał ci głowy przykładami GSP, ponieważ nie zmieniają się one zbytnio przy użyciu takich obiektów.

Jestem pewien, że mogą istnieć całe rozdziały książek napisanych na ten temat, ale mam nadzieję, że daje to wgląd i widzisz, że odpowiedź na twoje pytanie (pytania) brzmi: Obiekty dowodzenia.

+2

+1 punkt na. Dobrze zrobione, nie wspominając o klasach domen mogą być również używane jako obiekty poleceń. Mimo że jest to możliwe, użycie obiektu poleceń oddziela ten problem. – dmahapatro

Powiązane problemy