Utilizzare un livello di servizio con MVC


13

Se un controller diventa troppo grasso e l'istanza del modello inizia a sommarsi, è possibile utilizzare un livello di servizio.

  • Se avvolgo semplicemente la logica all'interno di una classe di servizio, otterrò un sacco di servizi con uno / due metodi. Sembra un odore di codice. Qualche migliore pratica al riguardo?

  • Un servizio può istanziare modelli?

  • Se un servizio crea un'istanza di modelli, i servizi non possono essere testati in unità. Possono essere coperti solo da test di integrazione?

Risposte:


25

In "SOLID", "I" sta per Interface Segregation. L'idea generale di questo principio è quella di dividere le grandi interfacce in interfacce più piccole, più modulari. Nel servizio MVC normalmente avrebbe un'interfaccia su cui fare affidamento il controller. Non vuoi che i tuoi controllori sappiano dell'implementazione concreta di quel servizio. Pertanto, una serie di servizi con uno o due metodi è una buona cosa da avere.

I servizi normalmente restituiscono DTO in applicazioni di grandi dimensioni o modelli di dominio direttamente in applicazioni più piccole. DTO normalmente significa più lavoro, ma una migliore separazione delle preoccupazioni. Il flusso tipico è:

  • Il controller chiama il servizio
  • Il servizio restituisce un oggetto (sia esso un DTO, un modello di dominio o qualcos'altro)
  • Il controller associa il modello DTO / dominio a un modello vista

La mappatura può essere eseguita manualmente, ma la maggior parte degli sviluppatori preferisce utilizzare il framework di mappatura automatica come Automapper perché non ci piace scrivere codice idraulico e possiamo essere abbastanza pigri :-)

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

https://github.com/AutoMapper/AutoMapper

Una delle tante discussioni su stackoverflow relative all'uso di DTO e modelli di dominio: /programming/2680071/dto-or-domain-model-object-in-the-view-layer



AutoMapper viene fornito con una funzionalità di test unità integrata che consente di verificare tutte le routine di mappatura con una riga. L'autore di questo post non lo ha menzionato.
CodeART

Ma lui lo sa e l'ha usato. I commenti vanno un po 'in questo.
Daniel Little,

2
Molte classi con solo uno o due metodi di solito indicano che non sono coerenti. Un livello di servizio, se esiste, dovrebbe essere sottile con la maggior parte della logica nei modelli. Sembra piuttosto inutile legare la vista a un oggetto stupido che non è altro che una borsa di proprietà. Il modello in MVC dovrebbe essere il modello di dominio avanzato
Andy,

3

In MVC il Modello, non è solo un DTO o un insieme di Manager / Servizi, intende rappresentare i concetti che la tua applicazione sta modellando. Puoi considerarlo come l'intero dominio o la logica aziendale, inclusi stato e comportamenti. Ora dato che sappiamo che lo scopo del controller diventa un po 'più chiaro. Il suo compito è semplicemente tradurre i comandi nel Modello e il risultato nuovamente nelle viste. Questo di solito viene fatto sotto forma di ViewModels che sono diversi ma spesso confusi con il Modello in MVC.

Se non hai un modello ben definito, potresti essere arrivato al punto in cui la maggior parte di quella logica ora risiede nei controller stessi. A questo punto, per iniziare a ridurre le dimensioni dei controller, è possibile iniziare a riportare questa logica in oggetti manager o di servizio. Questi servizi in genere restituiscono e operano su oggetti DTO / Entity come. Quindi il controller diventa il livello di mappatura tra questi servizi e Visualizza modelli. Per alcuni buoni consigli sulla mappatura dai un'occhiata a questo articolo Amici non permettono agli amici di usare AutoMapper .

Per quanto riguarda le tue domande, la prima dipende molto dalle tue applicazioni. Dovrai eseguire il refactoring lungo il percorso che dovrebbe diventare più evidente dopo aver rimosso la logica dai controller. Per quanto riguarda i test, non vi è alcun problema nell'istanziare i modelli all'interno dei servizi, tuttavia se lo trovate difficile è probabilmente un segnale che è necessario suddividere il servizio in parti più piccole ciascuna con una sola responsabilità.


3

I controller dovrebbero contenere solo chiamate al modello (in cui si verifica la logica aziendale) e in base a tali chiamate assegnare dati per la vista (oggetti di informazioni o messaggi di errore), pertanto i controller saranno abbastanza piccoli anche per una pagina molto complessa, se il controller continua diventa molto grande dovresti pensare che forse quella pagina dovrebbe essere espansa in più pagine.

Tuttavia il modello può essere piuttosto grande ... la soluzione che ho trovato era avere una variabile all'interno del controller che indica quale modello caricare e per compiti specifici carico il modello specifico.

Prova a obbedire al modello del controller vista modello pulito in questo modo:

  • view: visualizza i dati
  • controller: raccoglie input utente, chiede al modello i dati richiesti e li rimanda alla vista
  • modello: interagisce con il database ed esegue azioni logiche per preparare le informazioni

-1

Trovo i servizi davvero utili per eseguire la logica che potrebbe essere necessaria per più di un controller o che non è abbastanza specifica per far parte del controller, oltre al fatto che impedisce ai miei controller di diventare troppo grandi e difficili da leggere. .

Personalmente non sono d'accordo con 'aaa' quando dice che "modello (dove la logica di bussiness accade)" poiché questo è il motivo per cui hai controller, a mio avviso i modelli devono essere semplici astrattori di dati in modo che il controller possa svolgere il compito necessario; di nuovo i servizi non dovrebbero essere coinvolti nell'attività di astrazione dei dati ...

sto solo dicendo che ....


1
Se il tuo modello è solo un dto sei caduto nel modello di dominio anemico antipattern martinfowler.com/bliki/AnemicDomainModel.html
Andy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.