Modello di duplicazione di classe?


11

Attualmente sto lavorando come sviluppatore solista sul mio progetto attuale. Ho ereditato il progetto da un altro sviluppatore, che da allora ha lasciato l'azienda. È un'applicazione web in stile controller vista modello in C #. Utilizza Entity Framework per la mappatura relazionale degli oggetti. E ci sono due diversi insiemi di classi per i tipi nel modello di dominio. Un set viene utilizzato per interagire con l'ORM e l'altro viene utilizzato come modelli nel sistema MVC. Ad esempio, potrebbero esserci due classi come segue:

public class Order{
    int ID{get;set;}
    String Customer{get;set;}
    DateTime DeliveryDate{get;set;}
    String Description{get;set;}
}

e

public class OrderModel{
    String Customer{get;set;}
    DateTime DeliveryDate{get;set;}
    String Description{get;set;}
    public OrderModel( Order from){
        this.Customer= from.Customer;
        // copy all the properties over individually
    }
    public Order ToOrder(){
        Order result =new Order();
        result.Customer = this.Customer;
        // copy all the properties over individually
    }

}

Posso pensare a diversi inconvenienti di questo approccio (più posti per cambiare codice se qualcosa cambia, più oggetti seduti in memoria, più tempo impiegato per copiare i dati), ma non sono sicuro di quali vantaggi ci siano. Più flessibilità per le classi del modello, suppongo? Ma ho potuto ottenerlo anche sottoclassando le classi di entità. La mia inclinazione sarebbe quella di unire questi due gruppi di classi, o possibilmente avere le classi del modello in sottoclassi delle classi di entità. Quindi mi sto perdendo qualcosa di importante qui? È un modello di design comune di cui non sono a conoscenza? Ci sono buone ragioni per non passare attraverso il refactor che sto contemplando?

AGGIORNARE

Alcune delle risposte qui mi stanno facendo capire che nella mia descrizione iniziale del progetto mancavano alcuni dettagli importanti. Esiste anche un terzo gruppo di classi esistenti nel progetto: le classi del modello di pagina. Sono quelli effettivamente utilizzati come modello a supporto della pagina. Contengono inoltre informazioni specifiche dell'interfaccia utente e che non verrebbero archiviate con un ordine nel database. Una classe di modello di pagina di esempio potrebbe essere:

public class EditOrderPagelModel
{
    public OrderModel Order{get;set;}
    public DateTime EarliestDeliveryDate{get;set;}
    public DateTime LatestAllowedDeliveryDate{get;set;}
}

Vedo totalmente l'utilità di questo terzo gruppo qui distinta, e non ho intenzione di fonderlo con qualcos'altro (anche se potrei rinominarlo).

Le classi nel gruppo di modelli sono attualmente utilizzate anche dall'API dell'applicazione, che sarei anche interessato a sentire input su se questa è una buona idea.

Vorrei anche ricordare che il cliente rappresentato qui come una stringa doveva semplificare l'esempio, non perché in realtà veniva rappresentato in quel modo nel sistema. Il sistema reale ha il cliente come un tipo distinto nel modello di dominio, con le sue proprietà


1
"Ho ereditato il progetto da un altro sviluppatore, che da allora ha lasciato la società" c'è un sito dedicato alle storie che iniziano così .

Per quanto riguarda l'aggiornamento: sembra troppo indiretto per non avere abbastanza benefici.
Robert Harvey,

@RobertHarvey A cosa ti riferisci come troppo indiretta?
Robert Ricketts,

1
The OrderModel. OrderViewModel (quello a cui probabilmente si sta riferendo come EditOrderPageModel) è sufficiente riferimento indiretto; vedi la mia risposta qui sotto.
Robert Harvey,

@RobertHarvey Sembra la risposta alla domanda che stavo davvero cercando di porre
Robert Ricketts,

Risposte:


16

Quindi mi sto perdendo qualcosa di importante qui?

Mentre questi sembrano la stessa cosa e rappresentano la stessa cosa nel dominio, non sono gli stessi oggetti (OOP).

Uno è il Ordernoto dalla parte di archiviazione dei dati del codice. L'altro è Ordercome noto dall'IU. Sebbene sia una piacevole coincidenza che queste classi abbiano le stesse proprietà, non sono garantite .

O per dargli un'occhiata da un'altra prospettiva, considera il Principio della singola responsabilità. La motivazione chiave qui è che "una classe ha una ragione per cambiare". Soprattutto quando si ha a che fare con framework pervasivi come un ORM e / o un framework UI, i propri oggetti devono essere ben isolati poiché le modifiche al framework spesso causeranno il cambiamento delle entità.

Legando le tue entità a entrambi i framework, stai peggiorando le cose.


7

Lo scopo del modello di visualizzazione è quello di fornire il disaccoppiamento in due modi: fornendo i dati nella forma richiesta dalla vista (indipendentemente dal modello) e (specialmente in MVVM) rimandando una parte o tutta la logica della vista dalla vista al modello di visualizzazione.

In un modello completamente normalizzato, il Cliente non verrebbe rappresentato nel Modello da una stringa, ma piuttosto da un ID. Il Modello, se necessita del nome del cliente, cercherebbe il nome dalla tabella Clienti, utilizzando l'ID cliente presente nella tabella Ordini.

Un modello di visualizzazione, d'altra parte, potrebbe essere più interessato Nameal cliente, non all'ID. Non è necessario per l'ID a meno che il Cliente non venga aggiornato nel Modello.

Inoltre, il modello di visualizzazione può, e di solito, assumere una forma diversa (a meno che non sia puro CRUD ). Un oggetto Modello vista fattura può avere nome cliente, indirizzi ed elementi pubblicitari, ma il modello contiene clienti e descrizioni.

In altre parole, le fatture non vengono normalmente archiviate nello stesso modo in cui vengono visualizzate.


3

Per certi versi hai ragione: si riferiscono entrambi allo stesso oggetto domaino, che viene chiamato order. Ma ti sbagli di gran lunga, non è una vera duplicazione di una rappresentazione diversa - originata da scopi diversi. Se vuoi mantenere il tuo ordine, ad es. Vuoi accedere a tutte le colonne. Ma non vuoi lasciarlo fuori. Oltre a spingere intere Entità attraverso il filo non è quello che vuoi davvero. Conosco casi in cui una raccolta di MB di è ordersstata spedita al client in cui sarebbero bastati pochi kb .

Per farla breve: ecco i motivi principali per cui vuoi farlo:

1) Incapsulamento: nascondere le informazioni dell'applicazione

2) I piccoli modelli sono veloci da serializzare e facili da trasmettere

3) Servono a scopi diversi, sebbene si sovrappongano, e quindi dovrebbero esserci oggetti diversi.

4) A volte ha senso avere per diverse query diversi oggetti valore . Non so come sia in C #, ma in Java è possibile utilizzare un POJO per raccogliere risultati. Se ho bisogno di un singolo orderutilizzo Order -Entity, ma se ho solo bisogno di alcune colonne piene di quantità sui dati, l'uso di oggetti più piccoli è più efficiente.


Nel modo in cui è strutturato il framework delle entità, le entità sono semplici vecchi oggetti C #, quindi inviarle via cavo non è un grosso problema. Vedo l'utilità di poter inviare solo una parte del contenuto di un ordine in alcune circostanze.
Robert Ricketts,

Uno o un gruppo non è il problema, come ho detto. Ma ci sono casi in cui hai MB di dati, che rallenta il tempo di caricamento. Pensa ai tempi di caricamento mobile
Thomas Junk

0

(Dichiarazione di non responsabilità: l'ho visto solo usato in questo modo. Potrei aver frainteso il vero scopo di farlo. Tratta questa risposta con sospetto.)

Ecco un altro bit mancante: la conversione tra Ordere OrderModel.

La Orderclasse è legata al tuo ORM, mentre OrderModelè legata al design del tuo modello di visualizzazione.

In genere, i due metodi saranno forniti "in modo magico" (a volte chiamato DI, IoC, MVVM o ancora un'altra cosa). Cioè, invece di implementare questi due metodi di conversione come parte di OrderModel, faranno invece parte di una classe dedicata all'interconversione di queste cose; quella classe sarà in qualche modo registrata con il framework in modo che il framework possa facilmente cercarla.

public class OrderModel {
    ...
    public OrderModel(Order from) { ... }
    public Order ToOrder() { ... }
}

Il motivo di ciò è che ogni volta che si verifica un passaggio da OrderModela Ordero viceversa, si sa che alcuni dati devono essere stati caricati o salvati in ORM.


Se li tengo entrambi in giro, vorrei sicuramente configurarli per rendere la conversione più automatizzata
Robert Ricketts,

@RobertRicketts La cosa che ho visto è simile a questa: IMvxValueConverter . Anche se potrei aver frainteso il suo scopo.
rwong
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.