80

In primo luogo, prima che qualcuno urlasse, ho avuto difficoltà a sintetizzarlo in un titolo semplice. Un altro titolo potrebbe essere stato "Qual è la differenza tra un modello di dominio e un modello MVC?" o "Cos'è un modello?"Dove si inserisce il "livello della logica aziendale" in un'applicazione MVC?

Concettualmente, capisco che un modello sia il dato utilizzato dalle viste e dal controller. Oltre a ciò, sembra esserci una grande quantità di opinioni divergenti su ciò che costituisce il modello. Che cos'è un modello di dominio, un modello di app, un modello di vista, un modello di servizio, ecc.

Ad esempio, in una domanda recente che ho chiesto del modello di repository, mi è stato detto che il repository è vuoto parte del modello. Tuttavia, ho letto altre opinioni che il modello dovrebbe essere separato dal modello di persistenza e dal livello della logica di business. Dopotutto, il modello di Repository non dovrebbe disaccoppiare il metodo di persistenza concreto dal modello? Altre persone dicono che c'è una differenza tra il modello Dominio e il modello MVC.

Facciamo un semplice esempio. AccountController incluso nel progetto predefinito MVC. Ho letto diverse opinioni sul fatto che il codice Account incluso è di scarsa progettazione, viola SRP, ecc. Ecc. Se si dovesse progettare un modello di abbonamento "corretto" per un'applicazione MVC, quale sarebbe?

Come si separano i servizi ASP.NET (provider di appartenenze, provider di ruoli, ecc.) Dal modello? O lo faresti affatto?

Per come la vedo io, il modello dovrebbe essere "puro", forse con logica di validazione .. ma dovrebbe essere separato dalle regole aziendali (oltre alla convalida). Ad esempio, supponiamo tu abbia una regola aziendale che dice che qualcuno deve essere inviato via email quando viene creato un nuovo account. Questo a mio parere non appartiene davvero al modello. Allora, dove appartiene?

Qualcuno deve fare attenzione a questo problema?

+0

"na domanda recente ho chiesto il Pattern Repository, mi è stato detto di punto in bianco che il repository è parte del modello "Se ricordo bene, il rispondente ha cambiato la sua risposta. Questo è sbagliato. – jfar

+0

Quindi perché ho avuto difficoltà a trovare un buon titolo;) –

+1

Ecco perché dovresti fare quattro domande separate. – jfar

risposta

65

Il modo in cui l'ho fatto - e non sto dicendo che è giusto o sbagliato, è avere la mia vista e poi un modello che si applica alla mia vista. Questo modello ha solo ciò che è rilevante per il mio punto di vista - incluse annotazioni di dati e regole di convalida. Il controller contiene solo la logica per la costruzione del modello. Ho un livello di servizio che ospita tutte le logiche di business. I miei controller chiamano il mio livello di servizio. Oltre quello è il mio livello di repository.

Gli oggetti del mio dominio sono alloggiati separatamente (nel loro progetto, in realtà). Hanno le loro annotazioni di dati e le regole di convalida. Il mio repository convalida gli oggetti nel mio dominio prima di salvarli nel database. Poiché ogni oggetto nel mio dominio eredita da una classe base che ha la validazione incorporata, il mio repository è generico e convalida tutto (e richiede che erediti dalla classe base).

Si potrebbe pensare che avere due serie di modelli sia duplicazione di codice, ed è in una certa misura. Ma esistono casi perfettamente ragionevoli in cui l'oggetto dominio non è appropriato per la vista.

Il caso specifico è quando si lavora con carte di credito - Devo richiedere un cvv durante l'elaborazione di un pagamento, ma non posso memorizzare il cvv (è una multa di $ 50.000 per farlo). Ma voglio anche che tu possa modificare la tua carta di credito: cambio di indirizzo, nome o data di scadenza. Ma non hai intenzione di darmi il numero o il cvv quando lo modifichi, e certamente non ho intenzione di mettere il numero della tua carta di credito in chiaro sulla pagina. Il mio dominio ha questi valori richiesti per il salvataggio di una nuova carta di credito perché me li dai, ma il mio modello di modifica non include nemmeno il numero della carta o cvv.

Un altro vantaggio per molti livelli è che se architettato correttamente, è possibile utilizzare structuremap o un altro contenitore IoC e scambiare i pezzi senza influire negativamente sull'applicazione.

A mio parere, il codice del controller deve essere solo il codice mirato alla vista. Mostra questo, nascondi quello, ecc. Il livello di servizio dovrebbe contenere la logica di business per la tua app. Mi piace avere tutto in un posto, quindi è facile cambiare o modificare una regola aziendale. Il livello del repository dovrebbe essere relativamente stupido - privo di logica aziendale e solo interrogare i dati e restituire gli oggetti del dominio. Separando i modelli di visualizzazione dal modello di dominio, si ha molta più flessibilità quando si tratta di regole di convalida personalizzate. Significa anche che non devi scaricare tutti i dati nella tua vista nei campi nascosti e spostarli avanti e indietro tra il client e il server (o ricostruirlo sul backend). Il vostro modello vista sarà quindi ospitare solo le informazioni rilevanti per la vista - e può essere personalizzato per avere Caccio per la logica vista o conteggi o enumerazioni in modo che la vista in sé non è ingombra di istruzioni logiche complicate come

<% if (!String.IsNullOrEmpty(Model.SomeObject.SomeProperty) && 
    Model.SomeObject.SomeInt == 3 && ...) { %> 

Mentre tutto sembra distribuito e sovradimensionato, ha lo scopo di essere architettato in questo modo. È perfetto? non proprio. Ma io lo preferisco ad alcuni progetti precedenti di chiamare repository dal controller e avere la logica di business mescolata nel controller, nel repository e nel modello.

+0

+1 josh. questo è "quasi" un facsimile di come facciamo le cose. –

+0

Quasi uno specchio di ciò che ho nella nostra applicazione MVC aziendale. Un'architettura N-Tier. L'app MVC interagisce solo con oggetti business e servizi nelle aree N-Tier. –

+0

Principalmente lo stesso qui. Progetti separati per definizioni, modelli, viewmodels, DAL, ecc. L'unica differenza è che il mio DAL include la logica per appiattire i dati per il web per ottimizzare la distribuzione di dati complessi per report o visualizzazioni personalizzate dei clienti. Ora evito di tenere le cose nella cache delle applicazioni per le tabelle di ricerca, ecc. Con le farm Web e le nuvole di Azure in gioco. –

16

Mi sono spesso chiesto come esattamente gli elementi MVC si adattino a una struttura di applicazioni Web tradizionale, in cui sono presenti viste (pagine), controller, servizi e oggetti dati (modello). Come hai detto, ci sono molte versioni di questo.

Credo che la confusione esista a causa dell'architettura sopra dichiarata e ampiamente accettata, che utilizza il modello di "modello di dominio anemico" (presunto). Non entrerò in molti dettagli sulla "anti-patternness" del modello anemico dei dati (puoi guardare uno dei miei sforzi per spiegare le cose here (basato su Java, ma rilevante per qualsiasi lingua)). Ma in breve, significa che il nostro modello contiene solo dati e la logica aziendale è collocata in servizi/gestori.

Ma supponiamo di avere domain driven architecture, e i nostri oggetti di dominio sono come dovrebbero essere - con logica sia statale che commerciale. E in questa prospettiva dominio-driven cose vengono perfezionati:

  • la vista è l'interfaccia utente
  • controllore raccoglie gli ingressi dell'interfaccia utente, invochi metodi sul modello, e restituisce una risposta alla UI
  • il modello è i nostri componenti aziendali: la gestione dei dati, ma anche la logica di business.

Immagino che risponda alle vostre domande principali. Le cose si complicano quando aggiungiamo altri livelli, come il livello del repository. Spesso viene suggerito che debba essere invocato dalla logica di business inserita nel modello (e quindi ogni oggetto di dominio ha un riferimento a un repository). Nell'articolo che ho linkato, sostengo che questa non è una buona pratica.E che in effetti non è una brutta cosa avere un livello di servizio. A proposito, la progettazione basata su domini non esclude il livello di servizio, ma dovrebbe essere "sottile" e solo coordinando gli oggetti di dominio (quindi nessuna logica aziendale).

Per il paradigma del modello di dati anemici, che è ampiamente adottato (nel bene e nel male), il modello sarebbe sia il livello di servizio che i propri oggetti di dati.

+1

+1 Parlato come uno sviluppatore java ;-) –

+0

Punto eccellente! Un'osservazione: c'è lo stesso pasticcio con i servizi. Almeno i servizi possono essere Servizi applicativi e Servizi di dominio. Il servizio applicativo è solo un involucro sottile, che raccoglie informazioni dai repository, ecc. Il servizio di dominio fornisce la logica di business, ovvero l'utilizzo di una combinazione di modelli di dominio o roba che non sempre si adatta al modello di dominio. – Artru

2

Il pattern MVC e il framework Asp.net non fanno distinzione su cosa dovrebbe essere il Modello.

Gli esempi propri di MS includono le classi di persistenza nel modello. La tua domanda sull'appartenenza al modello. Questo dipende Le classi del tuo modello sono di proprietà di qualcosa?Esiste un collegamento tra chi effettua l'accesso e quali dati vengono visualizzati? C'è il filtraggio dei dati parte di un sistema di permessi che è modificabile? Chi ha aggiornato o modificato un oggetto parte del tuo dominio come se qualcun altro debba vederlo o qualcosa del genere per il supporto back-end?

Anche l'esempio di email dipende. Hai familiarità con eventi di dominio o eventi in particolare? Disponi di un servizio separato per l'invio di email? L'atto di inviare un'e-mail parte del tuo dominio o è una preoccupazione a livello di applicazione al di fuori dell'ambito del tuo sistema? L'interfaccia utente deve sapere se un'email è stata inviata con successo o no? Le e-mail che non riescono a inviare hanno bisogno di nuovi tentativi? Il contenuto dell'email inviata deve essere archiviato per supporto o requisiti del servizio clienti?

Questi tipi di domande sono eccessivamente ampi e soggettivi ma sto rispondendo in modo tale che tu e tutti quelli che ti hanno votato possano capirlo.

Le vostre esigenze/tempistiche/risorse sono tutte immerse nell'architettura del vostro sistema. Anche lo revenue model può avere un effetto. Devi anche considerare il modello per il quale stai girando. DDD è molto diverso rispetto alle applicazioni di tipo persistence-as-model e tutte le slop intermedie sono valide anche per determinate app. Stai girando per testare l'app? Tutto ciò ha un effetto.

3

A mio parere,

Modello -

Non deve contenere la logica di business, dovrebbe essere pluggable (WCF come scenario). È usato per legare per visualizzare così, dovrebbe avere proprietà.

Business Logic -

dovrebbe essere messo in "Layer Servizi di dominio", è strato separato del tutto. Inoltre, aggiungerà un ulteriore livello qui "Servizi applicativi".

I servizi app si collegano al livello dei servizi di dominio per applicare la logica di business e infine restituire il modello.

Quindi, controller chiederà Application Service per il modello e il flusso andrà come,

Controller->Application Services(using domain services)->Model 
Problemi correlati