Użyj warstwy usługi z MVC

13

Jeśli kontroler staje się zbyt gruby, a tworzenie instancji modelu zaczyna się sumować, można zastosować warstwę usługi.

  • Jeśli po prostu zawiążę logikę w klasie usług, otrzymam kilka usług za pomocą jednej / dwóch metod. To przypomina zapach kodu. Jakieś najlepsze praktyki w tym zakresie?

  • Czy usługa może tworzyć modele?

  • Jeśli usługa tworzy modele, usług nie można testować jednostkowo. Mogą być objęte jedynie testami integracyjnymi?

Danidacar
źródło

Odpowiedzi:

25

W „SOLID” „I” oznacza segregację interfejsu. Cała idea tej zasady polega na dzieleniu dużych interfejsów na mniejsze, bardziej modułowe. W usłudze MVC normalnie interfejs miałby polegać na kontrolerze. Nie chcesz, aby Twoi administratorzy wiedzieli o konkretnej implementacji tej usługi. Dlatego dobrze jest mieć kilka usług z jedną lub dwiema metodami.

Usługi zwykle zwracają DTO w dużych aplikacjach lub modelach domen bezpośrednio w mniejszych aplikacjach. DTO zwykle oznacza więcej pracy, ale lepszy podział problemów. Typowy przepływ to:

  • Kontroler wzywa usługę
  • Usługa zwraca obiekt (może to być DTO, model domeny lub coś innego)
  • Kontroler mapuje model DTO / domeny na model widoku

Mapowanie można wykonać ręcznie, ale większość programistów woli korzystać z frameworku automatycznego mapowania, takiego jak Automapper, ponieważ nie lubimy pisać kodu hydraulicznego i możemy być dość leniwi :-)

http://en.wikipedia.org/wiki/Interface_segregation_principle

https://github.com/AutoMapper/AutoMapper

Jedna z wielu dyskusji na temat przepełnienia stosu dotyczących użycia DTO i modeli domen: /programming/2680071/dto-or-domain-model-object-in-the-view-layer

CodeART
źródło
1
Byłbym ostrożny przy użyciu auto mapera tutaj uglybugger.org/software/post/…
Daniel Little
AutoMapper ma wbudowaną funkcję testowania jednostek, która pozwala zweryfikować wszystkie procedury mapowania za pomocą jednej linii. Autor tego postu nie wspomniał o tym.
CodeART
Ale on o tym wie i wykorzystał to. Komentarze do tego trochę się odnoszą.
Daniel Little
2
Wiele klas z tylko jedną lub dwiema metodami zwykle oznacza, że ​​nie są spójne. Warstwa usługi, jeśli istnieje, powinna być cienka, a większość elementów logicznych znajduje się w modelach. Wydaje się raczej bezcelowe wiązanie widoku z głupim przedmiotem, który jest niczym więcej niż torbą na własność. Model w MVC powinien być bogatym modelem domenowym, a nie anemicznym martinfowler.com/bliki/AnemicDomainModel.html
Andy
3

W MVC Model nie jest tylko DTO lub zestawem menedżerów / usług, ale ma reprezentować koncepcje, które modeluje twoja aplikacja. Możesz myśleć o tym jak o całej domenie lub logice biznesowej, w tym o stanie i zachowaniach. Teraz, gdy wiemy, że cel kontrolera staje się nieco jaśniejszy. Jego zadaniem jest po prostu przetłumaczenie poleceń na Model i wynik z powrotem na widoki. Zwykle odbywa się to w formie ViewModels, które są różne, ale często mylone z modelem w MVC.

Jeśli nie masz dobrze zdefiniowanego modelu, być może doszło do tego, że większość tej logiki znajduje się teraz w samych kontrolerach. W tym momencie, aby zacząć zmniejszać rozmiar kontrolerów, możesz zacząć wciągać tę logikę z powrotem do obiektów menedżera lub usług. Usługi te zazwyczaj zwracają się i działają na obiektach podobnych do DTO / Entity. Następnie kontroler staje się warstwą mapowania między tymi usługami a modelami widoku. Aby zapoznać się z kilkoma dobrymi wskazówkami dotyczącymi mapowania, zapoznaj się z tym artykułem Znajomi nie pozwalają znajomym korzystać z AutoMapper .

Jeśli chodzi o twoje pytania, pierwsze zależy w dużej mierze od twoich aplikacji. Po drodze trzeba będzie dokonać refaktoryzacji, co powinno stać się bardziej widoczne po usunięciu logiki ze sterowników. Jeśli chodzi o testowanie, nie ma problemu z tworzeniem modeli w ramach usług, jednak jeśli masz trudności z testowaniem, prawdopodobnie jest to tylko znak, że musisz podzielić usługę na mniejsze części, z których każda ma jedną odpowiedzialność.

Daniel Little
źródło
3

Kontrolery powinny zawierać tylko wywołania do modelu (gdzie zachodzi logika biznesowa) i na podstawie tych wywołań przypisywać dane do widoku (obiekty informacji lub komunikatów o błędach), dlatego kontrolery będą dość małe, nawet dla bardzo złożonej strony, jeśli kontroler nadal staje się bardzo duży, powinieneś pomyśleć, że być może ta strona powinna zostać rozszerzona na więcej stron.

Nadal model może być dość duży ... Rozwiązaniem, które znalazłem, było posiadanie zmiennej wewnątrz kontrolera, która mówi, który model załadować, a dla określonych zadań ładuję określony model.

Spróbuj zastosować się do modelu kontrolera widoku modelu w następujący sposób:

  • widok: wyświetla dane
  • kontroler: zbiera dane wejściowe użytkownika, pyta model o żądane dane i odsyła je z powrotem do widoku
  • model: współdziała z bazą danych i wykonuje logiczne działania w celu przygotowania informacji
aaa
źródło
-1

Uważam, że usługi są naprawdę pomocne w wykonywaniu logiki, która może wymagać wykonania przez więcej niż jeden kontroler lub które nie są wystarczająco szczegółowe, aby być częścią kontrolera, poza tym, że powstrzymuje to moich kontrolerów przed zbyt dużym i trudnym do odczytania. .

Ja osobiście nie zgadzam się z „aaa”, kiedy mówi, że „model (tam, gdzie dzieje się logika biznesu)”, ponieważ z tego powodu masz kontrolerów, moim zdaniem modele muszą być prostymi modułami abstrakcyjnymi danych, aby administrator mógł wykonać potrzebne zadanie; znowu usługi nie powinny angażować się w zadanie pozyskiwania danych ...

tylko mówię cześć ....

Fredylg
źródło
1
Jeśli Twój model to tylko dto, wpadłeś
Andy