Model-View-Controller – modello attivo – comportamentoModel-View-Controller in Android
Nel 2011 circa, quando Android iniziò a diventare sempre più popolare, apparvero naturalmente delle domande sull’architettura. Dato che MVC era uno dei pattern UI più popolari a quel tempo, gli sviluppatori hanno cercato di applicarlo anche ad Android.
Se si cerca su StackOverflow per domande come “Come applicare MVC in Android”, una delle risposte più popolari afferma che in Android, un’attività è sia la vista che il controllore. Guardando indietro, questo suona quasi folle! Ma, a quel punto, l’enfasi principale era sul rendere il modello testabile e di solito la scelta dell’implementazione per la Vista e il Controllore dipendeva dalla piattaforma.
Come dovrebbe essere applicato MVC in Android
Oggi, la domanda su come applicare i modelli MVC ha una risposta che è più facile da trovare. Le Attività, i Frammenti e le Viste dovrebbero essere le Viste nel mondo MVC. I Controllori dovrebbero essere classi separate che non estendono o usano nessuna classe Android, e lo stesso vale per i Modelli.
Un problema sorge quando si collega il Controllore alla Vista, poiché il Controllore deve dire alla Vista di aggiornare. Nell’architettura passiva Model MVC, il Controller ha bisogno di tenere un riferimento alla View. Il modo più semplice per farlo, mentre ci si concentra sui test, è quello di avere un’interfaccia BaseView, che l’Activity/Fragment/View estenderebbe. Così, il controller avrebbe un riferimento alla BaseView.
Avantaggi
Il pattern Model-View-Controller supporta altamente la separazione delle preoccupazioni. Questo vantaggio non solo aumenta la testabilità del codice, ma lo rende anche più facile da estendere, permettendo un’implementazione abbastanza facile di nuove funzionalità.
Le classi Model non hanno alcun riferimento alle classi Android e sono quindi semplici da testare. Il Controller non estende o implementa alcuna classe Android e dovrebbe avere un riferimento a una classe di interfaccia della View. In questo modo, il test unitario del Controller è anche possibile.
Se le View rispettano il principio di responsabilità singola, allora il loro ruolo è solo quello di aggiornare il Controller per ogni evento dell’utente e solo visualizzare i dati dal Modello, senza implementare alcuna logica di business. In questo caso, i test UI dovrebbero essere sufficienti a coprire le funzionalità della vista.
La vista dipende dal controllore e dal modello
La dipendenza della vista dal modello comincia ad essere un lato negativo nelle viste complesse. Per minimizzare la logica nella vista, il modello dovrebbe essere in grado di fornire metodi testabili per ogni elemento che deve essere visualizzato. In un’implementazione attiva del Model, questo aumenta esponenzialmente il numero di classi e metodi, dato che sarebbero necessari degli osservatori per ogni tipo di dati.
Dato che la View dipende sia dal Controller che dal Model, i cambiamenti nella logica UI potrebbero richiedere aggiornamenti in diverse classi, diminuendo la flessibilità del pattern.
Chi gestisce la logica UI?
Secondo il pattern MVC, il Controller aggiorna il Model e la View riceve i dati da visualizzare dal Model. Ma chi decide come visualizzare i dati? È il Modello o la Vista? Consideriamo il seguente esempio: abbiamo un User
, con nome e cognome. Nella View abbiamo bisogno di visualizzare il nome dell’utente come “Lastname, Firstname” (ad esempio “Doe, John”).
Se il ruolo del Modello è solo quello di fornire i dati “grezzi”, significa che il codice nella View sarebbe:
String firstName = userModel.getFirstName();
String lastName = userModel.getLastName(); nameTextView.setText(lastName + ", " + firstName)
Quindi questo significa che sarebbe responsabilità della View gestire la logica UI. Ma questo rende la logica UI impossibile da testare unitariamente.
L’altro approccio è quello di avere il modello che espone solo i dati che devono essere visualizzati, nascondendo qualsiasi logica di business dalla vista. Ma poi, ci ritroviamo con modelli che gestiscono sia il business che la logica UI. Sarebbe testabile a livello di unità, ma poi il modello finisce per essere implicitamente dipendente dalla vista.
String name = userModel.getDisplayName(); nameTextView.setText(name);
Conclusione
Nei primi giorni di Android il pattern Model-View-Controller sembrava aver confuso un sacco di sviluppatori e portato a codice difficile, se non impossibile da testare a livello di unità.
La dipendenza della View dal Model e l’avere la logica nella View ha portato il nostro codice base ad uno stato dal quale era impossibile recuperare senza rifattorizzare completamente l’app. Qual è stato il nuovo approccio nell’architettura e perché? Scopritelo leggendo questo post sul blog.