Ist es ein "Mustergeruch", Getter wie "FullName" oder "FormattedPhoneNumber" in Ihr Modell einzufügen?


13

Ich arbeite an einer ASP.NET MVC-App und habe mir angewöhnt, in meine Modell- / Entitätsklassen hilfreiche und praktische Informationen einzufügen.

Beispielsweise:

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); }
    }
}

Ich frage mich, ob die Leute über das FullNameund die FormattedPhoneNumberGetter nachdenken .

Sie machen es sehr einfach, standardisierte Datenformate in der gesamten App zu erstellen, und sie scheinen viel wiederholten Code zu speichern. Es kann jedoch durchaus argumentiert werden, dass das Datenformat bei der Zuordnung von Modell zu Ansichtsmodell zu berücksichtigen ist.

Eigentlich habe ich diese Datenformate ursprünglich in meiner Service-Schicht angewendet, wo ich mein Mapping durchführe, aber es wurde zu einer Last, ständig Formatierer schreiben zu müssen, um sie dann an vielen verschiedenen Stellen anzuwenden. ZB verwende ich in den meisten Ansichten "Vollständiger Name" und es model.FullName = MappingUtilities.GetFullName(entity.FirstName, entity.LastName);schien viel weniger elegant als nur zu model.FullName = entity.FullNametippen (oder, wenn Sie etwas wie AutoMapper verwenden, möglicherweise gar nichts zu tippen).

Wo ziehen Sie die Linie, wenn es um die Datenformatierung geht? Ist es "okay", Daten in Ihrem Modell zu formatieren, oder ist das ein "Mustergeruch"?

Hinweis: Ich habe definitiv kein HTML in meinem Modell. Ich benutze dafür HTML-Helfer. Ich spreche ausschließlich von der Formatierung oder Kombination von Daten (und insbesondere von Daten, die häufig verwendet werden).


1
Dies kann praktisch sein. Aber hoffen und beten Sie, dass Sie diesen Code nie internationalisieren müssen.
btilly

@btilly, guter Punkt, aber ich bin zu 99,99% zuversichtlich, dass ich nicht.
Devuxer

Auf jeden Fall spezifisch für FullName und PhoneNumber. Geht es bei der Frage speziell um diese, weil sie inkonsistente Formate in verschiedenen Kulturen haben, oder hat @DanM einfach Beispiele ausgewählt, die sich für eine allgemeinere Frage nicht gut internationalisieren lassen?
Greg Jackson

@ Greg Jackson, auf jeden Fall die Leiter. Wie ammoQ betont hat, PhoneNumbergehört es wahrscheinlich zu einer eigenen Klasse (die ich jetzt implementiert habe). Aber FullNamewar es wirklich der Grund, warum ich die Frage geschrieben habe? Ich bin jedoch daran interessiert herauszufinden, ob es im Allgemeinen sinnvoll ist, Datenformatierungen / -kämme usw. in das Modell aufzunehmen, um Dinge zu erreichen, die für die gesamte Anwendung gelten. Aus den nachstehenden Antworten geht hervor, dass dies kein Gegenmuster ist, aber die Entscheidung sollte sorgfältig getroffen werden.
Devuxer

Beachten Sie, dass diese spezielle Formatierung für den vollständigen Namen möglicherweise auch nicht gut internationalisiert wird. In Ostasien beispielsweise ist die Namensreihenfolge umgekehrt wie in der westlichen Welt. Müssen Sie wirklich explizit damit umgehen? Möglicherweise nicht, aber denken Sie daran, dass Sie beim Formatieren von Daten auf viele knifflige Dinge stoßen werden.
Greg Jackson

Antworten:


9

In Ihrem Beispiel gefällt mir der FullNameGetter (aus all den Gründen, die Sie angegeben haben), aber der Getter FormattedPhoneNumber gefällt mir nicht. Der Grund ist: Es ist wahrscheinlich nicht so einfach (wenn Sie internationale Telefonnummern usw. haben) und wenn Sie die Logik für die Formatierung von Telefonnummern in eine Methode von setzen Member, müssen Sie wahrscheinlich umgestalten (oder vorsichtig kopieren und einfügen ), sobald Sie braucht eine formated Telefonnummer Institution, Vendorusw. zu.

EDIT: IMO wäre es besser, eine PhoneNumberKlasse mit einem FormattedGetter zu haben.


+1 und danke. Aber was ist, wenn ich meinen Formatierungscode für die Telefonnummer tatsächlich in eine Erweiterungsmethode setze? Dann könnte jedes Modell es verwenden, und es würde kein Refactoring oder Kopieren / Einfügen geben. Diese Lösung würde sich immer noch viel weniger wiederholen als das Anwenden des Formatierers auf jede Telefonnummer, die in jeder Ansicht angezeigt wird.
Devuxer

3
Die Verwendung einer Erweiterungsmethode wäre ein schneller Weg zum Antipattern "funktionale Zersetzung". Mit einer Erweiterungsmethode (für die StringKlasse, nehme ich an) "bringen" Sie der StringKlasse bei, wie Telefonnummern formatiert werden. Ist es wirklich Aufgabe der StringKlasse, über Telefonnummern Bescheid zu wissen? Ich glaube nicht. In diesem Sinne sind Erweiterungsmethoden syntaktischer Zucker, um etwas, das eindeutig nicht objektorientiert ist, so aussehen zu lassen, wie es war.
user281377

1
Okay, vergiss, dass ich die Erweiterungsmethode gesagt habe. Stellen Sie sich vor, ich hätte die Utility-Methode oder die Formatierungsklasse angegeben. Ich sage nur, dass Refactoring / Copy-Paste nicht notwendig sein sollte, unabhängig davon, ob ich einen Model-Getter habe oder die Formatierung woanders mache.
Devuxer

1
Und ich mag die Idee einer PhoneNumberKlasse. Ich habe sowieso geplant, weil ich auch eine PhoneTypeImmobilie besitze.
Devuxer

Ich mag die Idee, PhoneNumbereine Instanzklasse zu haben, nicht, weil die Daten nativ sind string. Vielmehr sollte es eine statische Klasse mit Methoden wie sein public static string Format(string phoneNumber, PhoneNumberStyle style).
Herr Anderson

5

Die Dinge, die Sie beim Schreiben von Code beachten müssen: Ist es richtig? Ist es lesbar Ist es effizient? Ist es wartbar? Ich würde, wie @btilly sagte, argumentieren, dass es aufgrund der kulturspezifischen Formatierung nicht wartbar ist, aber die Frage scheint allgemeiner zu sein.

Durch die Verwendung solcher Zugriffsmethoden wird der Code besser lesbar. Je nachdem, wie Sie ihn verwenden, werden andere Teile des Codes möglicherweise wesentlich sauberer. Meiner Meinung nach riecht das überhaupt nicht. Es würde anfangen zu riechen, wenn Sie Formatierungs-Accessoren für irgendeine Art von Zeichenkette hätten, die Sie vielleicht drucken möchten ( public string FirstLastName; public string FullName; public string FullNameWithMiddleInitial; public string PhoneNumberWithAreaCode; public string PhoneNumberWithoutAreaCode; public string PhoneNumberWithCountryCode;usw.)

Oder anders ausgedrückt: Wenn Sie ein Muster verwenden, riecht Ihr Code nicht automatisch nach einem Muster. Sie müssen es missbrauchen, wenn Sie dieses Attribut verdienen möchten.


Danke, Greg. +1. Ich stimme Ihnen zu, wenn es darum geht, jede Kombination zusammenzustellen. Ich versuche wirklich nur, den saubersten Weg zu finden, um zu standardisieren, wie Daten angezeigt werden.
Devuxer

3

Verstößt gegen das Prinzip der einheitlichen Verantwortung. Warum nicht eine Rufnummernklasse machen, etc ...?


Okay, dem stimme ich tatsächlich zu (siehe Diskussion unter ammoQs Antwort), aber sollte ich auch eine FullNameKlasse machen?
Devuxer

Ja, Sie sollten, aber Sie sollten die Schreibweise von "FullName" zu "FoolName" korrigieren. Oder vielleicht "PersonalName", da es sich um den Namen einer Person handelt und nicht um einen vollständigen Namen.
Kevin Cline

1
"Ja wirklich?" Was genau ist daran falsch, wenn nicht erwartet wird, dass die Klasse wächst? Selbst wenn es wächst, wie schwer wäre es dann, neu zu faktorisieren?
Job

@DanM: Dann ist es das, wonach Sie fragen, dh Sie bitten sie, ihren vollständigen legalen Namen einzugeben. Wenn Sie nach dem Vornamen sortieren, sortieren Sie wirklich nach dem ersten Buchstaben (dann nach dem zweiten usw.) des ersten Namens (dann nach dem nächsten usw.), sodass die Namen unabhängig davon gleich sortiert werden.
Matt Ellen


1

Für Ihr Beispiel halte ich es nicht für zu umfangreich, bestimmte Formate zu verwenden. Es ist ein oder zwei und alle Teile der Anwendung verwenden das gleiche Format.

Wenn Sie die gleichen Daten an verschiedenen Orten haben, an denen unterschiedliche Formate erforderlich sind , bricht diese Entscheidung zusammen .

In diesem Fall wäre ich versucht, die MemberKlasse auf Folgendes zurückzubringen:

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

Und dann machen Sie verschiedene Adapter für jedes Ziel. Angenommen, die Informationen wurden im CSV-Format benötigt:

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

Immer vorausgesetzt, Sie haben die Daten bereinigt, sodass keine Kommas usw. in den Zeichenfolgen enthalten sind.

Der Adapter muss keine Erweiterungsmethode sein, aber für diesen Fall scheint er zu passen.


Es ist schon eine Weile her, dass ich C # geschrieben habe, aber es gibt sicherlich Serialisierungsklassen, die damit umgehen können, anstatt mühsam Methoden wie toCSV immer und immer und immer und immer und immer und immer und immer und immer und immer und immer zu schreiben und immer und immer und immer und immer und immer ...
Kevin Cline

@ Kevin Cline: Es hängt davon ab, was Sie an jedem Waschbecken benötigen. Wenn sie nur serialisiertes XML benötigen, ist das in Ordnung. Viele Systeme tun dies nicht. Wenn es so oft gemacht werden muss over, dann stimmt etwas nicht mit dem Design.
Peter K.

Normalerweise müssten viele Klassen serialisiert werden. Es sollte möglich sein, eine einzelne CSV oder einen anderen Serializer zu schreiben, der die meisten Klassen über Reflektion verarbeiten kann, anstatt sie wie in Ihrem Beispiel von Hand zu codieren.
Kevin Cline

@ Kevin Cline: Einverstanden gewaltsam! Ich habe gerade etwas sehr Spezifisches für die gestellte Frage geschrieben. Konkrete, einfache Beispiele erklären die Dinge tendenziell besser.
Peter K.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.