Class Duplication Pattern?

9

Attualmente sto lavorando come sviluppatore solista per il mio progetto attuale. Ho ereditato il progetto da un altro sviluppatore, che da allora ha lasciato la società. È un'applicazione web in stile model-view-controller in C #. Utilizza Entity Framework per la mappatura relazionale di oggetti. E ci sono due diversi gruppi di classi per i tipi nel modello di dominio. Un set viene utilizzato per interagire con l'ORM e l'altro viene utilizzato come modello 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
    }

}

Riesco a pensare a diversi inconvenienti a questo approccio (più posti per cambiare codice se qualcosa cambia, più oggetti in memoria, più tempo impiegato per copiare dati in giro), ma non sono sicuro di quali siano i vantaggi qui. Più flessibilità per le classi modello, suppongo? Ma potrei ottenere questo anche sottoclassi delle classi di entità. La mia inclinazione sarebbe quella di unire questi due gruppi di classi, o possibilmente fare in modo che le classi modello siano sottoclassi delle classi di entità. Quindi mi manca qualcosa di importante qui? Si tratta di uno schema di progettazione comune di cui non sono a conoscenza? Ci sono buone ragioni per non passare con il refactor che sto contemplando?

Aggiorna

Alcune delle risposte qui mi stanno facendo capire che la mia descrizione iniziale del progetto mancava di alcuni dettagli importanti. Esiste anche un terzo gruppo di classi esistenti nel progetto: le classi del modello di pagina. Sono quelli che vengono effettivamente utilizzati come modello che supporta la pagina. Contengono inoltre informazioni specifiche per l'interfaccia utente e non vengono archiviate con un ordine nel database. Una classe del 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 che è distinto qui, 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 se fosse una buona idea.

Vorrei anche menzionare che il cliente rappresentato come una stringa qui era per semplificare l'esempio, non perché è effettivamente rappresentato in quel modo nel sistema. Il sistema attuale ha il cliente come un tipo distinto nel modello di dominio, con le sue proprietà

    
posta Robert Ricketts 04.05.2015 - 16:46
fonte

4 risposte

16

So am I missing something important here?

YES

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

Uno è il Order come noto dalla parte di memorizzazione dei dati del codice. L'altro è il Order come noto dall'interfaccia utente. Mentre è una piacevole coincidenza che queste classi abbiano le stesse proprietà, non sono garantite a

.

O per dare un'occhiata da un'altra prospettiva, considera il Principio di Responsabilità Unica. Il motivatore chiave qui è che "una classe ha una ragione per cambiare". Specialmente quando si tratta di framework pervasivi come un ORM e / o un framework UI, gli oggetti devono essere ben isolati poiché le modifiche al framework spesso causano il cambiamento delle entità.

Legando le tue entità a entrambi i framework, lo stai facendo molto peggio.

    
risposta data 04.05.2015 - 17:14
fonte
7

Lo scopo del View Model è di fornire il disaccoppiamento in due modi: fornendo dati nella forma richiesta dalla View (indipendente dal modello) e (specialmente in MVVM) spingendo parte o tutta la logica della View indietro dal modello View to the View.

In un modello completamente normalizzato, il Cliente non sarebbe rappresentato nel Modello da una stringa, ma piuttosto da un ID. Il modello, se ha bisogno del nome del cliente, dovrebbe cercare il nome dalla tabella Clienti, utilizzando l'ID cliente trovato nella tabella Ordini.

Un modello di vista, d'altra parte, potrebbe essere più interessato al Name del cliente, non all'ID. Non ha bisogno dell'ID, a meno che il Cliente non sia aggiornato nel Modello.

Inoltre, il Modello di vista può, e di solito ha 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 normalmente non vengono memorizzate nello stesso modo in cui vengono visualizzate.

    
risposta data 04.05.2015 - 17:25
fonte
2

Per certi versi hai ragione: entrambi riferiscono allo stesso domainobject, che è chiamato order . Ma tu hai torto, non è una vera duplicazione di una diversa rappresentazione - originata da scopi diversi. Se desideri mantenere il tuo ordine, ad es. vuoi accedere a ciascuna colonna. Ma tu non vuoi farlo uscire all'esterno. Oltre a spingere intere Entità attraverso il filo non è quello che vuoi veramente. Conosco casi, in cui una raccolta di MB di orders è stata inviata al client dove sarebbero bastati pochi kb .

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

1) Incapsulamento - Nascondere le informazioni dell'applicazione

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

3) Esse servono a scopi diversi, sebbene si sovrappongano e pertanto dovrebbero esserci oggetti diversi.

4) A volte ha senso avere per diverse Query differenti Oggetti valore . Non so come sia in C #, ma in Java è possibile usare un POJO per raccogliere i risultati. Se ho bisogno di un singolo order uso l' Ordine -Entity, ma se ho bisogno solo di alcune colonne piene di quantità sui dati, usare più piccoli è più efficiente.

    
risposta data 04.05.2015 - 18:16
fonte
0

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

Ecco un altro bit mancante: la conversione tra Order e OrderModel .

La classe Order è legata al tuo ORM, mentre OrderModel è legata al design del tuo View Model.

Tipicamente, i due metodi saranno forniti "in modo magico" (a volte chiamati DI, IoC, MVVM o ancora un'altra cosa). Cioè, invece di implementare questi due metodi di conversione come parte di OrderModel , essi invece appartengono a 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 cercarlo.

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

La ragione per fare questo è che ogni volta che c'è un passaggio da OrderModel a Order o viceversa, sai che alcuni dati devono essere stati caricati da o salvati in ORM.

    
risposta data 04.05.2015 - 18:09
fonte

Leggi altre domande sui tag