Logica di presentazione del refattore dal modello

2

Ho visto questo pattern utilizzato in una notevole quantità di applicazioni MVC. Supponiamo di avere un modello utente con i metodi:

  • hasSessionExpired
  • displaySessionExpired

Il primo metodo (hasSessionExpired) cerca nel database se la sessione dell'utente è scaduta e restituisce true o false e il secondo chiama il primo metodo e restituisce una stringa HTML che in pratica dice "Expired" con un carattere rosso o "Active "con un carattere verde in base all'output di hasSessionExpired.

Nel controller c'è una chiamata all'oggetto User per recuperare tutti gli utenti che vengono restituiti come una matrice di oggetti User, questo array viene inviato alla vista.

Quindi nella vista, l'array viene iterato e viene chiamato il metodo displaySessionExpired per ogni oggetto dell'array.

C'è qualcosa che ha un odore fondamentalmente sbagliato in questo approccio, dal momento che il modello ha una logica di presentazione nel metodo displaySessionExpired e l'esito di tale logica è basato sul risultato di una query di database eseguita in quel momento. Ciò ovviamente rende le classi modello con migliaia di linee afflitte da mix di presentazione e logica aziendale che a lungo termine rendono l'applicazione più difficile da mantenere.

Come dovrebbe essere refactored quindi c'è una chiara separazione delle preoccupazioni?

    
posta thearchitect 03.09.2015 - 01:58
fonte

2 risposte

1

Il 'displaySessionExpired' sul tuo modello semplicemente non appartiene a questo. È responsabilità del tuo modello gestire la logica, ma COME viene visualizzato (quale testo e quale colore) è la responsabilità della vista. Spetta alla vista chiamare hasSessionExpired e prendere il risultato da visualizzare.

    
risposta data 03.09.2015 - 10:55
fonte
1

Penso che ci sia un concetto mancante qui, che è UserSession. Un utente può avere più UserSession (ma solo una sessione attiva alla volta)

Quindi, se eseguo il refactoring, sarebbe qualcosa di simile a questo (in .NET):

public class UserSession
{
    private DateTime _expireTime;
    //Other properties

    public bool IsActive()
    {
        return _expireTime > DateTime.Now;
    }
}

public class User
{
    private List<UserSession> _sessions;

    public bool IsLoggedIn()
    {
        return _sessions.Any(s => s.IsActive());
    }
}

Questi due sono nel livello dominio

I controller MVC otterranno l'elenco degli utenti dal database, con UserSession caricato nell'Utente. Se ti preoccupi dell'impatto sulle prestazioni del caricamento di tutte le UserSession, puoi caricare solo UserSession attiva.

Nella visualizzazione MVC, per visualizzare chi sta effettuando l'accesso, chi no:

@foreach (var user in users)
{
    if(user.IsLoggedIn())
    {
        <span style='background-color: green' >@user.Name</span>
    }
    else
    {
        <span style='background-color: red' >@user.Name</span>
    }
}

O ancora meglio se disponi di un modello di visualizzazione che contiene tutti i dati necessari per essere visualizzati nella vista:

public class UserStatusViewModel
{
    public string Name { get; set; }
    public bool IsLoggedIn { get; set; }
}

La mappatura da utente a utenteStatusViewModel viene eseguita nel servizio controller / applicazione. La vista ora dipende dal modello di vista anziché dal modello

    
risposta data 03.09.2015 - 11:10
fonte

Leggi altre domande sui tag