MVC: il controllore infrange il principio di responsabilità singola?

15

Il principio di responsabilità unica afferma che "una classe dovrebbe avere una ragione per il cambiamento".

Nel modello MVC, il lavoro del Controller consiste nel mediare tra la vista e il modello. Offre un'interfaccia per la vista per segnalare le azioni eseguite dall'utente sulla GUI (ad esempio consentendo alla vista di chiamare controller.specificButtonPressed() ), ed è in grado di chiamare i metodi appropriati sul modello per manipolarli o richiamarne le operazioni (ad es. model.doSomething() ).

Questo significa che:

  • Il controller deve conoscere la GUI, al fine di offrire alla View un'interfaccia adatta a segnalare le azioni degli utenti.
  • Inoltre, è necessario conoscere la logica del modello per poter richiamare i metodi appropriati sul modello.

Ciò significa che ha due motivi per cambiare : una modifica nella GUI e una modifica nella logica aziendale.

Se la GUI cambia, ad es. viene aggiunto un nuovo pulsante, il controller potrebbe dover aggiungere un nuovo metodo per consentire alla vista di riportare un utente che preme su questo pulsante.

E se la logica di business nel Modello cambia, il Controller potrebbe dover cambiare per richiamare i metodi corretti sul Modello.

Pertanto, il controller ha due possibili motivi per cambiare . Rompe SRP?

    
posta Aviv Cohn 04.05.2014 - 00:01
fonte

5 risposte

12

Se continui di conseguenza a ragionare sull'SRP, verrai notato che "la singola responsabilità" è in realtà un termine spugnoso. Il nostro cervello umano è in qualche modo in grado di distinguere tra diverse responsabilità e molteplici responsabilità possono essere astratte in una responsabilità "generale". Ad esempio, immagina in una comune famiglia di 4 persone che un membro della famiglia è responsabile della preparazione della colazione. Ora, per fare questo, bisogna far bollire le uova e tostare il pane e, naturalmente, preparare una buona tazza di tè verde (sì, il tè verde è il migliore). In questo modo puoi rompere "facendo colazione" in pezzi più piccoli che sono insieme astratti per "fare colazione". Si noti che ogni pezzo è anche una responsabilità che potrebbe ad es. essere delegato a un'altra persona.

Ritorno al MVC: se la mediazione tra il modello e la vista non è una responsabilità ma due, allora quale sarebbe il prossimo livello di astrazione sopra, combinando questi due? Se non riesci a trovarne uno non lo hai estratto in modo corretto o non ce n'è uno che significa che hai capito bene. E credo che sia il caso di un controller, che gestisce una vista e un modello.

    
risposta data 04.05.2014 - 01:11
fonte
8

Se una classe ha "due possibili motivi per cambiare", allora sì, viola l'SRP.

Un controller dovrebbe di solito essere leggero e avere la sola responsabilità di manipolare il dominio / modello in risposta ad un evento guidato dalla GUI. Possiamo considerare ciascuna di queste manipolazioni fondamentalmente come casi d'uso o funzionalità.

Se viene aggiunto un nuovo pulsante sulla GUI, il controller deve solo cambiare se quel nuovo pulsante rappresenta una nuova funzionalità (cioè contrario allo stesso pulsante che esisteva sullo schermo 1 ma non esisteva ancora sullo schermo 2, e viene quindi aggiunto alla schermata 2). Dovrebbe esserci anche un nuovo cambiamento corrispondente nel modello, per supportare questa nuova funzionalità / funzionalità. Il controllore ha ancora la responsabilità di manipolare il dominio / modello in risposta a qualche evento guidato dalla GUI.

Se la logica di business nel modello cambia a causa della correzione di un bug e richiede la modifica del controller, questo è un caso speciale (o forse il modello sta violando il principio open-closed). Se la logica di business nel modello cambia per supportare alcune nuove funzionalità / funzionalità, allora questo non ha necessariamente un impatto sul controller - solo se il controller deve esporre tale funzionalità (che sarebbe quasi sempre il caso, altrimenti perché dovrebbe essere aggiunto a il modello di dominio se non sarà usato). Quindi, in questo caso, anche il controller deve essere modificato per supportare la manipolazione del modello di dominio in questo nuovo modo in risposta ad alcuni eventi guidati dalla GUI.

Se il controller deve cambiare perché, ad esempio, il livello di persistenza viene cambiato da un file flat a un database, il controller sta sicuramente violando SRP. Se il controller funziona sempre allo stesso livello di astrazione, ciò può aiutare a raggiungere SRP.

    
risposta data 04.05.2014 - 00:49
fonte
4

Il controller non viola SRP. Come dichiari, la sua responsabilità è di mediare tra i modelli e la vista.

Detto questo, il problema con il tuo esempio è che stai legando i metodi del controllore alla logica nella vista, cioè controller.specificButtonPressed . Denominando i metodi in questo modo si lega il controller alla GUI, non si è riusciti ad astrarre correttamente le cose. Il controller dovrebbe occuparsi dell'esecuzione di azioni specifiche, ad esempio controller.saveData o controller.retrieveEntry . Aggiungere un nuovo pulsante nella GUI non significa necessariamente aggiungere un nuovo metodo al controller.

Premendo un pulsante nella vista, si intende fare qualcosa, ma qualunque cosa sia potrebbe facilmente essere stata attivata in un numero qualsiasi di altre vie o anche non attraverso la vista.

Dall'articolo di Wikipedia su SRP

Martin defines a responsibility as a reason to change, and concludes that a class or module should have one, and only one, reason to change. As an example, consider a module that compiles and prints a report. Such a module can be changed for two reasons. First, the content of the report can change. Second, the format of the report can change. These two things change for very different causes; one substantive, and one cosmetic. The single responsibility principle says that these two aspects of the problem are really two separate responsibilities, and should therefore be in separate classes or modules. It would be a bad design to couple two things that change for different reasons at different times.

Il controller non è interessato a ciò che è nella vista solo quando viene chiamato uno dei suoi metodi che fornisce dati specificati alla vista. Ha solo bisogno di conoscere le funzionalità del modello fino a quando sa che è necessario chiamare metodi che avranno. Non sa niente di più.

Sapere che un oggetto ha un metodo disponibile per chiamare non è lo stesso di conoscere la sua funzionalità.

    
risposta data 04.05.2014 - 02:49
fonte
1

Una sola responsabilità dei controllori deve essere il contratto che media tra la vista e il modello. La vista dovrebbe essere responsabile solo per la visualizzazione, il modello dovrebbe essere responsabile solo della logica di business. È responsabilità dei responsabili del controllo colmare queste due responsabilità.

Va tutto bene, ma allontanarsi un po 'dal mondo accademico; un controller in MVC è generalmente composto da molti metodi di azione più piccoli. Queste azioni generalmente corrispondono a cose che una cosa può fare. Se sto vendendo prodotti, probabilmente avrò un ProductController. Quel controller avrà azioni come GetReviews, ShowSpecs, AddToCart ect ...

La vista ha l'SRP di visualizzazione dell'interfaccia utente e parte di quell'interfaccia utente include un pulsante che dice AddToCart.

Il controller ha l'SRP di conoscere tutte le viste e i modelli coinvolti nel processo.

L'azione AddToCart dei controller ha lo SRP specifico per conoscere tutti coloro che devono essere coinvolti quando un articolo viene aggiunto a un carrello.

Il Modello prodotto ha l'SRP della logica del prodotto di modellazione e il Modello ShoppingCart ha l'SRP della modellazione di come gli elementi vengono salvati per il checkout successivo. Il Modello utente ha un SRP di modellazione dell'utente che sta aggiungendo cose al proprio carrello.

Puoi e dovresti riutilizzare i modelli per portare a termine la tua attività e quei modelli devono essere accoppiati a un certo punto del tuo codice. Il controller controlla ogni singolo modo in cui avviene l'accoppiamento.

    
risposta data 02.07.2017 - 06:05
fonte
0

I controllori in realtà hanno una sola responsabilità: alterare lo stato delle applicazioni in base all'input dell'utente.

A controller can send commands to the model to update the model's state (e.g., editing a document). It can also send commands to its associated view to change the view's presentation of the model (e.g., by scrolling through a document).

source: wikipedia

Se invece stai utilizzando i "controller" in stile Rails (che destreggiano tra istanze di record attive e modelli stupidi) , allora ovviamente stanno rompendo SRP.

Quindi di nuovo, le applicazioni in stile Rails non sono realmente MVC per cominciare.

    
risposta data 05.05.2014 - 22:25
fonte

Leggi altre domande sui tag