come gestire le mutazioni del controller

5

Durante il processo di sviluppo, le cose cambiano continuamente (specialmente nelle prime fasi). I requisiti cambiano, l'interfaccia utente cambia, tutto cambia. Pagine che chiaramente appartenevano a un controller specifico, mutate in qualcosa di completamente diverso in futuro.

Ad esempio. Diciamo che abbiamo un sito web per la gestione dei progetti. Una pagina del sito web è stata dedicata alla gestione di esistenti e all'invito di nuovi membri di progetti specifici. Naturalmente, ho creato i controller dei membri annidati sotto progetti che avevano la responsabilità adeguata.

In seguito allo sviluppo, si è scoperto che era l'unica pagina che "configurava il progetto" in qualche modo, quindi sono state aggiunte funzionalità aggiuntive:

  • modifica della descrizione del progetto
  • imposta il progetto come predefinito
  • ...

In altre parole, questa pagina ha cambiato la sua responsabilità principale dalla gestione dei membri del progetto alla gestione del progetto stesso. Idealmente, questa pagina dovrebbe essere spostata nell'azione "modifica" del controller "progetti". Ciò significherebbe che tutte le richieste e le specifiche del controller devono essere nuovamente refactored. Vale la pena lo sforzo? Dovrebbe essere fatto?

Personalmente, sto davvero iniziando a non gradire la relazione 1-1 tra viste e controllori. La sua situazione comune è che abbiamo 1 pagina (vista) che gestisce 2 o più risorse differenti. Penso che dovremmo avere punti di vista completamente disaccoppiati dai controllori, ma i binari ci stanno dando del tempo difficile per raggiungere questo obiettivo.

So che AJAX può essere usato per risolvere questo problema, ma lo considero un'improvvisazione. Esiste un altro tipo di architettura (diversa da MVC) che disaccoppia le viste dai controllori?

    
posta Milovan Zogovic 17.11.2011 - 08:53
fonte

3 risposte

1

L'applicazione di composizione sull'ereditarietà ai controller è uno di quegli approcci con i quali non puoi sbagliare.

L'idea è di avere il controller più sottile possibile. Il controller dovrebbe solo definire i processi di richiesta / risposta, ma qualsiasi cosa che si verifichi nel mezzo sarà definita al di fuori della classe.

Ad esempio, se disponi di un controller che ha filtrato una raccolta di Product istanze in base a un determinato criterio, applica l'IVA al prezzo base e quindi produci una rappresentazione tabellare, CSV o JSON, ti ritroverai con le seguenti classi:

  1. Una classe che accetta l'oggetto richiesta e restituisce una raccolta appropriata di istanze Product ; questa classe si occupa di sapere come costruire una query appropriata in base alla richiesta in entrata (come l'interrogazione di prodotti basata su un mix di valori di attributo).
  2. Una classe che accetta una raccolta Product , elabora ciascuna voce e restituisce la raccolta risultante; questa classe si occupa di prendere l'IVA specificata di un prodotto e applicarla sul prezzo base.
  3. Una classe che accetta l'oggetto richiesta in entrata e una raccolta Product e produce una risposta appropriata; questa classe si occupa di capire se produrre una risposta HTML, CSV o JSON della raccolta.
  4. Il tuo controller attuale che crea semplicemente una rete di comunicazione tra le tre classi; questa classe specifica infine la nozione di raccolta, elaborazione e visualizzazione del modello Product in modo appropriato.

Il fatto è che i controller spesso presentano un sacco di comportamenti complessi, ma in questo modo il comportamento viene preso in considerazione in diversi componenti che vengono definiti e testati indipendentemente. Semplicemente mescolando in classi diverse e cambiando poche righe di codice, il comportamento del controller cambia drasticamente. Non ho alcuna esperienza con Ruby, ma da quello che so questo può essere ottenuto includendo e mescolando diversi moduli e forse anche una macro o due per il condimento.

Un buon esempio di questo approccio sono i controller generici di Django. Sono solo tipi composti da diversi mixin in cui ogni mixin definisce determinati comportamenti ed espone gli attributi di classe ei metodi di istanza che possono essere specificati / sovrascritti per configurare il loro comportamento. I controller generici forniti sono solo una particolare combinazione di mixin esistenti che sono adatti per un particolare problema.

Un altro buon esempio è Android con i suoi controller. Un Acitivty viene chiamato dalla struttura della strumentazione ogni volta che l'attività deve rispondere a un certo tipo di richiesta (creare te stesso, iniziare te stesso, distruggere te stesso) con un determinato input, ma sta accadendo tutto su un thread dell'interfaccia utente che si aspetta che questi metodi siano elegante. Qualunque cosa sostanziale, come il numero di crunch, il recupero di dati su HTTP, la raccolta di dati dal DB, così via, viene effettivamente gestita da oggetti di alcuni tipi esterni che comunicano alcuni dati al controller chiamante. A volte, questa comunicazione è abbastanza generica da poter essere strutturata implementando interfacce e il comportamento relativo a ciascuna di esse è specificato in una classe anonima. Di nuovo, si finisce con un semplice controllore che collega solo una rete di comunicazione tra diversi oggetti per definire un comportamento complesso, ma il comportamento è definito in una forma compatta dalla quale è possibile capire facilmente cosa sta succedendo.

Questo è il riutilizzo del codice promesso dal principio di composizione: se il comportamento del controller deve essere migrato su un controller diverso o se un determinato tipo di comportamento deve essere condiviso tra più controllori, la composizione sull'ereditarietà ti dà la possibilità di fare così. E cosa c'è di meglio, applicando il principio di sostituzione di Liskov , le possibilità diventano infinite!

    
risposta data 16.03.2012 - 21:05
fonte
1

Bene, per mantenere il mio codice organizzato, io spesso:

  • decide di estrarre alcune logiche del controllore in una superclasse e di farne ereditare il controllore. In questo modo, i controllori finiscono per chiamare il metodo da esso e rimangono puliti, evitando la duplicazione

  • la stessa cosa potrebbe essere fatta includendo moduli nei tuoi controllori

  • una soluzione alternativa sarebbe utilizzare un componente di terze parti come Celle .

risposta data 17.11.2011 - 13:45
fonte
0

Spesso trovo questo problema anche io. Faccio un paio di cose per sistemarlo;

Faccio più cose che posso nei modelli, quindi non ingombrare i miei controller e di solito lo faccio quando clicchi su un progetto in / projects (progetti # index) andrà direttamente a / projects /: project_id / membri (membri # indice) invece di default / projects /: id (progetti # show). Il motivo è che i membri sono la risorsa principale nella pagina.

    
risposta data 17.11.2011 - 12:08
fonte

Leggi altre domande sui tag