È un "odore di modello" inserire getter come "FullName" o "FormattedPhoneNumber" nel tuo modello?


13

Sto lavorando su un'app ASP.NET MVC e ho preso l'abitudine di inserire quelli che sembrano getter utili e convenienti nelle mie classi di modello / entità.

Per esempio:

public class Member
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }

    public string FullName
    {
        get { return FirstName + " " + LastName; }
    }

    public string FormattedPhoneNumber
    {
        get { return "(" + PhoneNumber.Substring(0, 3) + ") " + PhoneNumber.Substring(3, 3) + "-" + PhoneNumber.Substring(6); }
    }
}

Mi chiedo che la gente pensi al FullNamee ai FormattedPhoneNumbergetter.

Semplificano la creazione di formati di dati standardizzati in tutta l'app e sembrano salvare un sacco di codice ripetuto, ma si potrebbe sicuramente sostenere che il formato dei dati è qualcosa che dovrebbe essere gestito nella mappatura da modello a modello di vista.

In effetti, stavo originariamente applicando questi formati di dati nel mio livello di servizio in cui eseguo la mia mappatura, ma stava diventando un peso dover costantemente scrivere i formattatori e applicarli in molti luoghi diversi. Ad esempio, utilizzo "Nome completo" nella maggior parte delle visualizzazioni e dover digitare qualcosa di simile in model.FullName = MappingUtilities.GetFullName(entity.FirstName, entity.LastName);tutto il luogo mi è sembrato molto meno elegante della semplice digitazione model.FullName = entity.FullName(o, se si utilizza qualcosa come AutoMapper, potenzialmente non si digita affatto).

Quindi, dove si disegna la linea quando si tratta di formattazione dei dati. È "ok" fare la formattazione dei dati nel tuo modello o è un "odore di pattern"?

Nota: sicuramente non ho HTML nel mio modello. Per questo uso gli helper HTML. Sto parlando rigorosamente di formattazione o combinazione di dati (e in particolare i dati utilizzati di frequente).


1
Fare questo può essere conveniente. Ma spera e prega che non devi mai internazionalizzare quel codice.
btilly

@btilly, buon punto, ma sono fiducioso circa il 99,99% che non lo farò.
Devuxer,

Specifico per FullName e PhoneNumber, sicuramente. La domanda riguarda specificamente quelli perché hanno formati incoerenti in culture diverse o @DanM ha semplicemente scelto esempi che non si internazionalizzano bene per una domanda più generale?
Greg Jackson,

@Greg Jackson, sicuramente la scala. Come sottolineato da AmmoQ, PhoneNumberprobabilmente appartiene alla sua stessa classe (che ora ho implementato). Ma è FullNamestato davvero quello che mi ha motivato a scrivere la domanda. Ma sono interessato a scoprire se, in generale, ha senso inserire la formattazione / pettinatura dei dati, ecc. Nel modello per cose che verranno applicate a livello di app. Dalle risposte che seguono, sembra che questo non sia un anti-schema, ma la decisione dovrebbe essere presa con cura.
Devuxer,

Tieni presente che questa formattazione specifica per il nome completo potrebbe anche non internazionalizzare bene. Nell'Asia orientale, ad esempio, l'ordine dei nomi è al contrario di quello che è nel mondo occidentale. Hai davvero bisogno di gestirlo esplicitamente? Forse no, ma tieni presente che ci sono molte cose difficili che ti imbatterai durante la formattazione dei dati.
Greg Jackson,

Risposte:


9

Nel tuo esempio, mi piace il FullNamegetter (per tutti i motivi che hai indicato) ma non mi piace il getter FormattedPhoneNumber. Il motivo è: probabilmente non è così facile (una volta che hai numeri di telefono internazionali ecc.) E se metti la logica per formulare i numeri di telefono in un metodo di Member, è probabile che dovrai refactoring (o copia e incolla caugh ) una volta che è necessario un numero di telefono formattato per Institution, Vendorecc.

EDIT: IMO sarebbe meglio avere una PhoneNumberclasse con un Formattedgetter.


+1 e grazie. E se inserissi effettivamente il codice di formattazione del mio numero di telefono in un metodo di estensione? Quindi qualsiasi modello potrebbe usarlo e non ci sarebbe alcun refactoring o copia / incolla. Questa soluzione sarebbe ancora molto meno ripetitiva rispetto all'applicazione del formatter per ogni numero di telefono che appare in ogni vista.
Devuxer,

3
L'uso di un metodo di estensione per questo sarebbe un modo rapido per l'antipasto "decomposizione funzionale". Usando un metodo di estensione (per la Stringclasse, presumo), tu "insegni" alla Stringclasse come formattare i numeri di telefono. È davvero responsabilità della Stringclasse conoscere i numeri di telefono? Io non la penso così. Usati in questo modo, i metodi di estensione sono zucchero sintattico per lasciare che qualcosa che chiaramente non è orientato agli oggetti sembri.
user281377,

1
Ok, dimentica che ho detto il metodo di estensione. Fai finta di aver detto metodo di utilità o classe di formattazione. Sto semplicemente dicendo che il refactoring / copia incolla non dovrebbe essere necessario, indipendentemente dal fatto che io abbia un modello getter o esegua la formattazione altrove.
Devuxer,

1
E mi piace l'idea di una PhoneNumberlezione. Ho intenzione di farlo comunque perché ho anche una PhoneTypeproprietà.
Devuxer,

Non mi piace l'idea di avere PhoneNumbercome classe di istanza perché i dati sono nativi string. Piuttosto, dovrebbe essere una classe statica con metodi simili public static string Format(string phoneNumber, PhoneNumberStyle style).
Mr Anderson,

5

Le cose che devi considerare quando scrivi il codice: è corretto? È leggibile? È efficiente? È mantenibile? Direi che, come accennato da @btilly, non è gestibile a causa della formattazione specifica della cultura, ma la domanda sembra essere più generale.

L'uso di accessori come questi rende il tuo codice più leggibile e, a seconda di come lo usi, potrebbe rendere più pulite altre parti del codice. Secondo me, questo non ha alcun odore. Comincerebbe a puzzare se avessi gli accessori di formattazione per qualsiasi tipo di stringa che potresti voler stampare ( public string FirstLastName; public string FullName; public string FullNameWithMiddleInitial; public string PhoneNumberWithAreaCode; public string PhoneNumberWithoutAreaCode; public string PhoneNumberWithCountryCode;, ecc.)

Oppure, per dirla in altro modo, l'uso di un pattern non rende automaticamente il tuo codice "odore di pattern". Devi abusarne se vuoi guadagnare quell'attributo.


Grazie Greg. +1. Sono d'accordo con te sul mettere ogni combinazione. Sto davvero solo cercando di trovare il modo più pulito per standardizzare la visualizzazione dei dati.
Devuxer,

3

Rompe il principio della singola responsabilità. Perché non fare una classe di numero di telefono, ecc ...?


Okay, in realtà sono d'accordo (vedi la discussione sotto la risposta di AmmoQ), ma dovrei anche fare un corso FullName?
Devuxer,

Sì, dovresti, ma dovresti correggere l'ortografia da "FullName" a "FoolName". O forse "PersonalName", dato che è il nome di una persona e non completo.
Kevin Cline,

1
Veramente? A meno che non ci si aspetti che la classe data cresca, che cosa c'è di esattamente sbagliato? Anche se cresce, quanto sarebbe difficile ripensare il fattore?
Giobbe

@DanM: Quindi è quello che chiedi, cioè chiedi loro di digitare il loro nome legale completo. Se stai ordinando per nome, stai davvero ordinando la prima lettera (quindi la seconda, e così via) del primo nome (quindi il successivo, quindi così via), quindi i nomi ordineranno lo stesso indipendentemente.
Matt Ellen,


1

Per il tuo esempio, non lo vedo come un affare troppo grande per utilizzare formati specifici. È una o due e tutte le parti dell'applicazione utilizzano lo stesso formato.

Il punto in cui tale decisione inizia a essere scomposta è quando si hanno gli stessi dati che vanno in luoghi diversi che richiedono formati diversi .

Se ciò accadesse, sarei tentato di Memberriportare la classe a:

public class Member
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }  
}

E quindi eseguire adattatori diversi per ciascun target. Ad esempio, supponiamo che le informazioni fossero richieste in formato CSV:

public static class CSVMemberAdapter
{
    public static string ToCSV(this Member mbr)
    {
         return mbr.Id + "," + mbr.LastName + "," + mbr.FirstName, "," mbr.PhoneNumber;
    }
}

Supponendo sempre di aver disinfettato i dati in modo che non ci siano virgole ecc. Nelle stringhe.

L'adattatore non deve essere un metodo di estensione, ma per questo caso fittizio sembra adattarsi.


È passato un po 'di tempo da quando ho scritto C #, ma sicuramente ci sono classi di serializzazione che possono gestirlo, invece di scrivere noiosamente metodi come toCSV ancora e ancora e ancora e ancora e ancora e ancora e ancora e ancora e ancora e ancora e ancora e ancora e ancora e ancora e ancora ...
Kevin Cline il

@kevin cline: dipende da ciò di cui hai bisogno in ogni lavandino. Se tutto ciò di cui hanno bisogno è un XML serializzato, va bene. Molti sistemi no. Se deve essere fatto overtante volte, c'è qualcosa che non va nel design.
Peter K.

in genere ci sarebbero molte classi da serializzare. Dovrebbe essere possibile scrivere un singolo CSV o un altro serializzatore in grado di gestire la maggior parte delle classi tramite la riflessione, anziché codificarle manualmente come nell'esempio.
Kevin Cline,

@kevin cline: violentemente d'accordo! Stavo solo scrivendo qualcosa di molto specifico per la domanda posta. Esempi concreti e semplici tendono a spiegare meglio le cose.
Peter K.
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.