it-swarm.com.de

Sollen wir Typen für alles definieren?

Kürzlich bin ich auf ein Problem mit der Lesbarkeit meines Codes gestoßen.
Ich hatte eine Funktion, die eine Operation ausführte und eine Zeichenfolge zurückgab, die die ID dieser Operation zur späteren Bezugnahme darstellt (ähnlich wie OpenFile in Windows, das ein Handle zurückgibt). Der Benutzer würde diese ID später verwenden, um den Vorgang zu starten und sein Ende zu überwachen.

Die ID musste aus Gründen der Interoperabilität eine zufällige Zeichenfolge sein. Dies führte zu einer Methode mit einer sehr unklaren Signatur wie folgt:

public string CreateNewThing()

Dies macht die Absicht des Rückgabetyps unklar. Ich dachte, ich würde diesen String in einen anderen Typ einwickeln, der seine Bedeutung klarer macht:

public OperationIdentifier CreateNewThing()

Der Typ enthält nur die Zeichenfolge und wird immer dann verwendet, wenn diese Zeichenfolge verwendet wird.

Es ist offensichtlich, dass der Vorteil dieser Funktionsweise in der Typensicherheit und der klareren Absicht liegt, aber es wird auch viel mehr Code und Code erstellt, der nicht sehr idiomatisch ist. Einerseits mag ich die zusätzliche Sicherheit, aber es schafft auch viel Unordnung.

Halten Sie es aus Sicherheitsgründen für eine gute Praxis, einfache Typen in eine Klasse einzubinden?

144
Ziv

Grundelemente wie string oder int haben in einer Geschäftsdomäne keine Bedeutung. Eine direkte Folge davon ist, dass Sie möglicherweise fälschlicherweise eine URL verwenden, wenn eine Produkt-ID erwartet wird, oder eine Menge verwenden, wenn Sie einen Preis erwarten .

Dies ist auch der Grund, warum Object Calisthenics Challenge Primitive als eine seiner Regeln enthält:

Regel 3: Wickle alle Primitiven und Strings ein

In der Sprache Java) ist int ein Grundelement, kein reales Objekt, daher folgt es anderen Regeln als Objekte. Es wird mit einer Syntax verwendet, die nicht objektorientiert ist int allein ist nur ein Skalar, hat also keine Bedeutung. Wenn eine Methode ein int als Parameter verwendet, muss der Methodenname die gesamte Arbeit zum Ausdrücken der Absicht ausführen. Wenn dieselbe Methode eine Stunde als Parameter benötigt Es ist viel einfacher zu sehen, was los ist.

Das gleiche Dokument erklärt, dass es einen zusätzlichen Vorteil gibt:

Kleine Objekte wie Hour oder Money geben uns auch einen offensichtlichen Ort, um Verhalten zu platzieren, das sonst in anderen Klassen verstreut gewesen wäre .

In der Tat ist es bei Verwendung von Grundelementen normalerweise äußerst schwierig, die genaue Position des Codes in Bezug auf diese Typen zu verfolgen, was häufig zu schwerwiegenden Codeduplizierungen führt. Wenn es eine Price: Money - Klasse gibt, ist es natürlich, die Bereichsprüfung darin zu finden. Wenn stattdessen ein int (schlimmer noch ein double) zum Speichern von Produktpreisen verwendet wird, wer sollte den Bereich validieren? Das Produkt? Der Rabatt? Der Wagen?

Ein dritter Vorteil, der im Dokument nicht erwähnt wird, ist die Möglichkeit, den zugrunde liegenden Typ relativ einfach zu ändern. Wenn mein ProductId heute short als zugrunde liegenden Typ hat und ich später stattdessen int verwenden muss, wird der zu ändernde Code wahrscheinlich nicht die gesamte Codebasis umfassen.

Der Nachteil - und das gleiche Argument gilt für jede Regel der Objektkalisthenik-Übung - ist, dass, wenn schnell zu überwältigend wird, um eine Klasse für alles zu erstellen . Wenn ProductProductPrice enthält, das von PositivePrice erbt, das von Price erbt, das wiederum von Money erbt, ist dies keine saubere Architektur. sondern ein komplettes Durcheinander, bei dem ein Betreuer jedes Mal ein paar Dutzend Dateien öffnen sollte, um eine einzige Sache zu finden.

Ein weiterer zu berücksichtigender Punkt sind die Kosten (in Codezeilen) für die Erstellung zusätzlicher Klassen. Wenn die Wrapper unveränderlich sind (wie es normalerweise sein sollte), bedeutet dies, dass Sie, wenn wir C # nehmen, mindestens Folgendes im Wrapper haben müssen:

  • Der Immobilienmakler,
  • Sein Hintergrundfeld,
  • Ein Konstruktor, der den Wert dem Hintergrundfeld zuweist.
  • Ein benutzerdefiniertes ToString(),
  • XML-Dokumentationskommentare (was viel von Zeilen macht),
  • Ein Equals und ein GetHashCode überschreiben (auch viel LOC).

und schließlich, wenn relevant:

  • A DebuggerDisplay Attribut,
  • Eine Überschreibung der Operatoren == Und !=,
  • Eventuell eine Überlastung des impliziten Konvertierungsoperators, um nahtlos in und aus dem gekapselten Typ zu konvertieren.
  • Code-Verträge (einschließlich der Invariante, die mit ihren drei Attributen eine ziemlich lange Methode ist),
  • Mehrere Konverter, die während der XML-Serialisierung, der JSON-Serialisierung oder beim Speichern/Laden eines Werts in/aus einer Datenbank verwendet werden.

Einhundert LOC für einen einfachen Wrapper machen ihn ziemlich unerschwinglich, weshalb Sie sich auch der langfristigen Rentabilität eines solchen Wrappers völlig sicher sein können. Der Begriff des Umfangs erklärt von Thomas Junk ist hier besonders relevant. Das Schreiben von hundert LOCs zur Darstellung eines ProductId, das in Ihrer gesamten Codebasis verwendet wird, ist sehr nützlich. Das Schreiben einer Klasse dieser Größe für einen Code, der drei Zeilen innerhalb einer einzigen Methode bildet, ist viel fragwürdiger.

Schlussfolgerung:

  • Schließen Sie Grundelemente in Klassen ein, die in einem Geschäftsbereich der Anwendung eine Bedeutung haben, wenn (1) dies zur Reduzierung von Fehlern beiträgt, (2) das Risiko einer Codeduplizierung verringert oder (3) die spätere Änderung des zugrunde liegenden Typs unterstützt.

  • Schließen Sie nicht jedes Grundelement, das Sie in Ihrem Code finden, automatisch ein: In vielen Fällen ist die Verwendung von string oder int vollkommen in Ordnung.

In der Praxis kann es in public string CreateNewThing() hilfreich sein, eine Instanz der Klasse ThingId anstelle von string zurückzugeben, aber Sie können auch:

  • Gibt eine Instanz der Klasse Id<string> Zurück, dh ein Objekt vom generischen Typ, das angibt, dass der zugrunde liegende Typ eine Zeichenfolge ist. Sie haben den Vorteil der Lesbarkeit, ohne den Nachteil, dass Sie viele Typen pflegen müssen.

  • Gibt eine Instanz der Klasse Thing zurück. Wenn der Benutzer nur die ID benötigt, kann dies einfach durchgeführt werden mit:

    var thing = this.CreateNewThing();
    var id = thing.Id;
    
153

Ich würde das scope als Faustregel verwenden: Je enger der Umfang des Erzeugens und Konsums eines solchen values ist, desto weniger wahrscheinlich ist es, dass Sie ein Objekt erstellen müssen, das diesen Wert darstellt.

Angenommen, Sie haben den folgenden Pseudocode

id = generateProcessId();
doFancyOtherstuff();
job.do(id);

dann ist der Umfang sehr begrenzt und ich würde keinen Sinn darin sehen, es zu einem Typ zu machen. Angenommen, Sie generieren diesen Wert in einer Ebene und übergeben ihn an eine andere Ebene (oder sogar an ein anderes Objekt). Dann wäre es durchaus sinnvoll, einen Typ dafür zu erstellen.

61
Thomas Junk

Bei statischen Systemen geht es darum, eine falsche Verwendung von Daten zu verhindern.

Es gibt offensichtliche Beispiele für Typen, die dies tun:

  • sie können den Monat einer UUID nicht erhalten
  • sie können nicht zwei Zeichenfolgen multiplizieren.

Es gibt subtilere Beispiele

  • sie können nicht für etwas mit der Länge des Schreibtisches bezahlen
  • sie können keine HTTP-Anfrage mit dem Namen einer Person als URL stellen.

Wir könnten versucht sein, double sowohl für Preis als auch für Länge zu verwenden oder ein string sowohl für einen Namen als auch für eine URL zu verwenden. Aber das untergräbt unser fantastisches Typensystem und lässt diese Missbräuche die statischen Prüfungen der Sprache bestehen.

Wenn Pfund-Sekunden mit Newton-Sekunden verwechselt werden, kann dies schlechte Ergebnisse zur Laufzeit haben.


Dies ist insbesondere bei Zeichenfolgen ein Problem. Sie werden häufig zum "universellen Datentyp".

Wir sind es gewohnt, hauptsächlich Textschnittstellen mit Computern zu erstellen, und wir erweitern diese Benutzerschnittstellen (Benutzeroberflächen) häufig auf Programmierschnittstellen (APIs). Wir denken an 34.25 als die Zeichen 34.25. Wir stellen uns ein Datum als Zeichen vor 05-03-2015. Wir stellen uns eine UUID als Zeichen vor 75e945ee-f1e9-11e4-b9b2-1697f925ec7b.

Dieses mentale Modell schadet jedoch der API-Abstraktion.

Die Wörter oder die Sprache, wie sie geschrieben oder gesprochen werden, scheinen in meinem Denkmechanismus keine Rolle zu spielen.

Albert Einstein

Ebenso sollten Textdarstellungen beim Entwerfen von Typen und APIs keine Rolle spielen. Vorsicht vor dem string! (und andere übermäßig generische "primitive" Typen)


Typen kommunizieren "welche Operationen sinnvoll sind."

Zum Beispiel habe ich einmal an einem Client mit einer HTTP REST API gearbeitet. REST, richtig gemacht, verwenden Sie Hypermedia-Entitäten, deren Hyperlinks auf verwandte Entitäten verweisen. In diesem Client waren nicht nur die Entitäten eingegeben (z. B. Benutzer, Konto, Abonnement), wurden auch die Links zu diesen Entitäten eingegeben (UserLink, AccountLink, SubscriptionLink). Die Links waren kaum mehr als Wrapper um Uri, aber die separaten Typen machten es unmöglich, es zu versuchen Um einen AccountLink zum Abrufen eines Benutzers zu verwenden. Wäre alles einfach gewesen Uri - oder noch schlimmer string - würden diese Fehler nur zur Laufzeit gefunden.

Ebenso verfügen Sie in Ihrer Situation über Daten, die nur für einen Zweck verwendet werden: zur Identifizierung eines Operation. Es sollte nicht für andere Zwecke verwendet werden, und wir sollten nicht versuchen, Operation mit zufälligen Zeichenfolgen zu identifizieren, die wir erstellt haben. Das Erstellen einer separaten Klasse erhöht die Lesbarkeit und Sicherheit Ihres Codes.


Natürlich können alle guten Dinge im Übermaß verwendet werden. Erwägen

  1. wie viel Klarheit es Ihrem Code hinzufügt

  2. wie oft es verwendet wird

Wenn ein "Datentyp" (im abstrakten Sinne) häufig für bestimmte Zwecke und zwischen Codeschnittstellen verwendet wird, ist er ein sehr guter Kandidat für eine separate Klasse auf Kosten der Ausführlichkeit.

34
Paul Draper

Ich stimme im Allgemeinen zu, dass Sie häufig einen Typ für Grundelemente und Zeichenfolgen erstellen sollten. Da die obigen Antworten jedoch in den meisten Fällen die Erstellung eines Typs empfehlen, werde ich einige Gründe auflisten, warum/wann nicht:

  • Performance. Ich muss mich hier auf die tatsächlichen Sprachen beziehen. Wenn in C # eine Client-ID kurz ist und Sie sie in eine Klasse einschließen, haben Sie gerade viel Overhead erstellt: Speicher, da sie jetzt 8 Byte auf einem 64-Bit-System und Geschwindigkeit ist, da sie jetzt auf dem Heap zugewiesen ist.
  • Wenn Sie Annahmen über den Typ treffen. Wenn eine Client-ID kurz ist und Sie eine Logik haben, die sie auf irgendeine Weise packt, treffen Sie normalerweise bereits Annahmen über den Typ. An all diesen Orten muss man jetzt die Abstraktion brechen. Wenn es ein Punkt ist, ist es keine große Sache, wenn es überall ist, finden Sie möglicherweise die Hälfte der Zeit, in der Sie das Primitiv verwenden.
  • Weil nicht jede Sprache typedef hat. Und für Sprachen, die dies nicht tun, und Code, der bereits geschrieben wurde, könnte eine solche Änderung eine große Aufgabe sein, die sogar Fehler verursachen könnte (aber jeder hat eine Testsuite mit guter Abdeckung, oder?).
  • In einigen Fällen verringert Lesbarkeit. Wie drucke ich das aus? Wie validiere ich das? Soll ich nach Null suchen? Sind alle Fragen, die Sie erfordern, einen Drill in die Definition des Typs.
10
ytoledano

Halten Sie es aus Sicherheitsgründen für eine gute Praxis, einfache Typen in eine Klasse einzubinden?

Manchmal.

Dies ist einer der Fälle, in denen Sie die Probleme abwägen müssen, die durch die Verwendung eines string anstelle eines konkreteren OperationIdentifier entstehen können. Was sind ihre Schwere? Was ist ihre Wahrscheinlichkeit?

Dann müssen Sie die Kosten für die Verwendung des anderen Typs berücksichtigen. Wie schmerzhaft ist es zu benutzen? Wie viel Arbeit ist es zu machen?

In einigen Fällen sparen Sie Zeit und Mühe, indem Sie einen netten Betontyp verwenden, gegen den Sie arbeiten können. In anderen Fällen ist es die Mühe nicht wert.

Im Allgemeinen denke ich, dass so etwas mehr getan werden sollte als heute. Wenn Sie eine Entität haben, die etwas in Ihrer Domäne bedeutet, ist es gut, diese als eigenen Typ zu haben, da sich diese Entität mit größerer Wahrscheinlichkeit mit dem Geschäft ändert/wächst.

10
Telastyn

Nein, Sie sollten keine Typen (Klassen) für "alles" definieren.

Aber wie andere Antworten besagen, ist es oft nützlich, dies zu tun. Sie sollten - wenn möglich bewusst - ein Gefühl oder ein Gefühl von zu viel Reibung aufgrund der Abwesenheit eines geeigneten Typs oder einer geeigneten Klasse entwickeln, während Sie Ihren Code schreiben, testen und warten. Für mich tritt zu viel Reibung auf, wenn ich mehrere primitive Werte als einen einzigen Wert konsolidieren möchte oder wenn ich die Werte validieren muss (dh bestimmen muss, welcher aller möglichen Werte des primitiven Typs gültigen Werten des entspricht 'impliziter Typ').

Ich habe festgestellt, dass Überlegungen wie das, was Sie in Ihrer Frage gestellt haben, für zu viel Design in meinem Code verantwortlich sind. Ich habe mir angewöhnt, bewusst zu vermeiden, mehr Code als nötig zu schreiben. Hoffentlich schreiben Sie gute (automatisierte) Tests für Ihren Code. Wenn ja, können Sie Ihren Code einfach umgestalten und Typen oder Klassen hinzufügen, wenn dies Nettovorteile für die laufende Entwicklung und bietet Pflege Ihres Codes .

Telastyns Antwort und Thomas Junks Antwort machen beide einen sehr guten Punkt über den Kontext und die Verwendung des relevanten Codes. Wenn Sie einen Wert in einem einzelnen Codeblock verwenden (z. B. Methode, Schleife, using Block), ist es in Ordnung, nur einen primitiven Typ zu verwenden. Es ist sogar in Ordnung, einen primitiven Typ zu verwenden, wenn Sie wiederholt und an vielen anderen Stellen eine Reihe von Werten verwenden. Aber je häufiger und häufiger Sie eine Reihe von Werten verwenden und je weniger genau diese Menge den Werten entspricht, die durch den primitiven Typ dargestellt werden, desto mehr sollten Sie in Betracht ziehen, die Werte in einer Klasse oder einem Typ zu kapseln.

7
Kenny Evitt

Idee hinter dem Umschließen primitiver Typen,

  • Festlegen einer domänenspezifischen Sprache
  • Begrenzen Sie Fehler von Benutzern, indem Sie falsche Werte übergeben

Natürlich wäre es sehr schwierig und nicht praktisch, es überall zu tun, aber es ist wichtig, die Typen dort einzuwickeln, wo es erforderlich ist.

Zum Beispiel, wenn Sie die Klasse Order haben,

Order
{
   long OrderId { get; set; }
   string InvoiceNumber { get; set; }
   string Description { get; set; }
   double Amount { get; set; }
   string CurrencyCode { get; set; }
}

Die wichtigen Eigenschaften zum Nachschlagen einer Bestellung sind hauptsächlich OrderId und InvoiceNumber. Und der Betrag und der CurrencyCode sind eng miteinander verbunden. Wenn jemand den CurrencyCode ändert, ohne den Betrag zu ändern, kann die Bestellung nicht mehr als gültig angesehen werden.

Daher ist es in diesem Szenario sinnvoll, nur OrderId, InvoiceNumber und eine Zusammenstellung für die Währung zu verpacken, und wahrscheinlich macht das Verpacken der Beschreibung keinen Sinn. Das bevorzugte Ergebnis könnte also so aussehen:

    Order
    {
       OrderIdType OrderId { get; set; }
       InvoiceNumberType InvoiceNumber { get; set; }
       string Description { get; set; }
       Currency Amount { get; set; }
    }

Es gibt also keinen Grund, alles einzuwickeln, sondern Dinge, die wirklich wichtig sind.

5

An der Oberfläche sieht es so aus, als müssten Sie lediglich eine Operation identifizieren.

Zusätzlich sagen Sie, was eine Operation tun soll:

um die Operation zu starten [und] um das Ende zu überwachen

Sie sagen es so, als ob dies "nur die Art und Weise ist, wie die Identifikation verwendet wird", aber ich würde sagen, dass dies Eigenschaften sind, die eine Operation beschreiben. Das klingt für mich nach einer Typdefinition, es gibt sogar ein Muster namens "Befehlsmuster", das sehr gut passt. .

Es sagt

das Befehlsmuster [...] wird verwendet, um alle Informationen zu kapseln, die zum Ausführen einer Aktion oder Auslösen eines Ereignisses erforderlich sind zu einem späteren Zeitpunkt .

Ich denke, das ist sehr ähnlich im Vergleich zu dem, was Sie mit Ihren Operationen machen wollen. (Vergleichen Sie die Phrasen, die ich in beiden Anführungszeichen fett geschrieben habe.) Anstatt eine Zeichenfolge zurückzugeben, geben Sie einen Bezeichner für ein Operation im abstrakten Sinne zurück, beispielsweise einen Zeiger auf ein Objekt dieser Klasse in oop.

In Bezug auf den Kommentar

Es wäre wtf-y, diese Klasse als Befehl zu bezeichnen und dann nicht die Logik darin zu haben.

Nein, würde es nicht. Denken Sie daran, dass Muster sehr abstrakt sind , so abstrakt, dass sie etwas meta sind. Das heißt, sie abstrahieren oft die Programmierung selbst und nicht irgendein Konzept der realen Welt. Das Befehlsmuster ist eine Abstraktion eines Funktionsaufrufs. (oder Methode) Als ob jemand die Pause-Taste direkt nach dem Übergeben der Parameterwerte und kurz vor der Ausführung gedrückt hätte, um später fortzufahren.

Das Folgende erwägt oop, aber die Motivation dahinter sollte für jedes Paradigma gelten. Ich möchte einige Gründe nennen, warum das Einfügen der Logik in den Befehl als eine schlechte Sache angesehen werden kann.

  1. Wenn Sie all diese Logik im Befehl hätten, wäre sie aufgebläht und chaotisch. Sie würden denken "na ja, all diese Funktionen sollten in separaten Klassen sein." Sie würden die Logik aus dem Befehl heraus umgestalten .
  2. Wenn Sie all diese Logik im Befehl hätten, wäre es schwierig zu testen und beim Testen in die Quere zu kommen. "Heiliger Mist, warum muss ich diesen Befehlsquatsch verwenden? Ich möchte nur testen, ob diese Funktion 1 ausspuckt oder nicht, ich nicht Ich möchte es später anrufen, ich möchte es jetzt testen! "
  3. Wenn Sie all diese Logik im Befehl hätten, wäre es nicht allzu sinnvoll, sich zu melden, wenn Sie fertig sind. Wenn Sie an eine Funktion denken, die standardmäßig synchron ausgeführt werden soll, ist es nicht sinnvoll, benachrichtigt zu werden, wenn die Ausführung abgeschlossen ist. Vielleicht starten Sie einen anderen Thread, weil Sie tatsächlich den Avatar im Kinoformat rendern möchten (möglicherweise benötigen Sie einen zusätzlichen Thread auf Raspberry Pi), vielleicht müssen Sie einige Daten von einem Server abrufen, ... was auch immer es ist, wenn es einen Grund dafür gibt Wenn Sie fertig sind, kann dies daran liegen, dass eine gewisse Asynchronität (ist das ein Wort?) vorliegt. Ich denke, ein Thread auszuführen oder einen Server zu kontaktieren ist eine Logik, die nicht in Ihrem Befehl sein sollte. Dies ist eher ein Meta-Argument und möglicherweise umstritten. Wenn du denkst, dass es keinen Sinn macht, sag es mir bitte in den Kommentaren.

Um es noch einmal zusammenzufassen: Mit dem Befehlsmuster können Sie Funktionen in ein Objekt einbinden, das später ausgeführt werden soll. Aus Gründen der Modularität (Funktionalität ist vorhanden, unabhängig davon, ob sie über einen Befehl ausgeführt wird oder nicht), Testbarkeit (Funktionalität sollte ohne Befehl testbar sein) und all den anderen Modewörtern, die im Wesentlichen die Forderung nach gutem Code ausdrücken, würden Sie die eigentliche Logik nicht setzen in den Befehl.


Da Muster abstrakt sind, kann es schwierig sein, gute Metaphern für die reale Welt zu finden. Hier ist ein Versuch:

"Hey Oma, könntest du bitte um 12 Uhr die Aufnahmetaste auf dem Fernseher drücken, damit ich die Simpsons auf Kanal 1 nicht vermisse?"

Meine Oma weiß nicht, was technisch passiert, wenn sie diesen Aufnahmetaster drückt. Die Logik ist anderswo (im Fernseher). Und das ist gut so. Die Funktionalität ist gekapselt und Informationen sind vor dem Befehl verborgen. Es ist ein Benutzer der API, nicht unbedingt Teil der Logik. Oh je, ich plappere wieder mit Modewörtern. Ich beende diese Bearbeitung jetzt besser.

5
null

Unpopuläre Meinung:

Normalerweise sollten Sie keinen neuen Typ definieren!

Das Definieren eines neuen Typs zum Umschließen eines Grundelements oder einer Basisklasse wird manchmal als Definieren eines Pseudotyps bezeichnet. IBM beschreibt dies als eine schlechte Praxis hier (sie konzentrieren sich in diesem Fall speziell auf den Missbrauch mit Generika).

Pseudo-Typen machen allgemeine Bibliotheksfunktionen unbrauchbar.

Die mathematischen Funktionen von Java können mit allen Zahlenprimitiven arbeiten. Wenn Sie jedoch einen neuen Klassenprozentsatz definieren (ein Double umschließen, das im Bereich von 0 bis 1 liegen kann), sind alle diese Funktionen nutzlos und müssen von Klassen umbrochen werden, die (noch schlimmer) über die interne Darstellung der Percentage-Klasse Bescheid wissen müssen .

Pseudotypen werden viral

Wenn Sie mehrere Bibliotheken erstellen, werden Sie häufig feststellen, dass diese Pseudotypen viral werden. Wenn Sie die oben genannte Percentage-Klasse in einer Bibliothek verwenden, müssen Sie sie entweder an der Bibliotheksgrenze konvertieren (ohne jegliche Sicherheit/Bedeutung/Logik/andere Gründe, die Sie für die Erstellung dieses Typs hatten), oder Sie müssen diese Klassen erstellen auch für die andere Bibliothek zugänglich. Infizieren Sie die neue Bibliothek mit Ihren Typen, bei denen möglicherweise ein einfaches Double ausreicht.

Nachricht zum Mitnehmen

Solange der Typ, den Sie verpacken, nicht viel Geschäftslogik benötigt, würde ich davon abraten, ihn in eine Pseudoklasse zu verpacken. Sie sollten eine Klasse nur umbrechen, wenn schwerwiegende geschäftliche Einschränkungen bestehen. In anderen Fällen sollte die korrekte Benennung Ihrer Variablen einen großen Beitrag zur Vermittlung von Bedeutung leisten.

Ein Beispiel:

Ein uint kann eine UserId perfekt darstellen, wir können weiterhin die in Java integrierten Operatoren für uints (wie ==) verwenden und wir benötigen keine Geschäftslogik, um den 'internen Status' des zu schützen Benutzeridentifikation.

4
Roy T.

Wie bei allen Tipps ist es die Fähigkeit zu wissen, wann die Regeln anzuwenden sind. Wenn Sie Ihre eigenen Typen in einer typgesteuerten Sprache erstellen, erhalten Sie eine Typprüfung. Im Allgemeinen wird das ein guter Plan sein.

NamingConvention ist der Schlüssel zur Lesbarkeit. Die beiden zusammen können die Absicht klar vermitteln.
Aber /// ist immer noch nützlich.

Also ja, ich würde sagen, erstellen Sie viele eigene Typen, wenn ihre Lebensdauer eine Klassengrenze überschreitet. Berücksichtigen Sie auch die Verwendung von Struct und Class, nicht immer Class.

3
phil soady