Ich bin ein großer Fan der statischen Typprüfung. Es verhindert, dass Sie dumme Fehler wie diese machen:
// java code
Adult a = new Adult();
a.setAge("Roger"); //static type checker would complain
a.setName(42); //and here too
Aber es hindert dich nicht daran, so dumme Fehler zu machen:
Adult a = new Adult();
// obviously you've mixed up these fields, but type checker won't complain
a.setAge(150); // nobody's ever lived this old
a.setWeight(42); // a 42lb adult would have serious health issues
Das Problem tritt auf, wenn Sie denselben Typ verwenden, um offensichtlich unterschiedliche Arten von Informationen darzustellen. Ich dachte, eine gute Lösung für dieses Problem wäre, die Integer
Klasse zu erweitern , nur um Fehler in der Geschäftslogik zu vermeiden, aber keine Funktionen hinzuzufügen. Beispielsweise:
class Age extends Integer{};
class Pounds extends Integer{};
class Adult{
...
public void setAge(Age age){..}
public void setWeight(Pounds pounds){...}
}
Adult a = new Adult();
a.setAge(new Age(42));
a.setWeight(new Pounds(150));
Wird dies als gute Praxis angesehen? Oder gibt es später unvorhergesehene technische Probleme mit einem derart restriktiven Design?
a.SetAge( new Age(150) )
Kompilieren Sie noch nicht ?new Age(...)
Objekt deklariert haben, können Sie es anWeight
keiner anderen Stelle einer Variablen vom Typ zuordnen . Es reduziert die Anzahl der Stellen, an denen Fehler auftreten können.Antworten:
Sie fragen im Wesentlichen nach einem Einheitensystem (nein, keine Einheitentests, "Einheit" wie in "physikalische Einheit", wie Meter, Volt usw.).
In Ihrem Code
Age
repräsentiert Zeit undPounds
repräsentiert Masse. Dies führt zu Dingen wie Einheitenumrechnung, Basiseinheiten, Präzision usw.Es gab / gibt Versuche, so etwas in Java zu bekommen, zum Beispiel:
Die beiden späteren scheinen in dieser Github-Sache zu leben: https://github.com/unitsofmeasurement
C ++ hat Einheiten über Boost
LabView wird mit einer Reihe von Einheiten geliefert .
Es gibt andere Beispiele in anderen Sprachen. (Änderungen sind willkommen)
Wie Sie oben sehen können, unterstützt eine Sprache umso mehr Einheiten, je wahrscheinlicher die Verwendung von Werten mit Einheiten ist. LabView wird häufig zur Interaktion mit Messgeräten verwendet. Daher ist es sinnvoll, eine solche Funktion in der Sprache zu haben, und die Verwendung dieser Funktion wird mit Sicherheit als gute Praxis angesehen.
Aber in jeder Hochsprache für allgemeine Zwecke, in der die Nachfrage nach einem solchen Maß an Strenge gering ist, ist dies wahrscheinlich unerwartet.
Meine Vermutung wäre: Leistung / Gedächtnis. Wenn Sie mit einer Menge von Werten befassen, der Overhead eines Objekts pro Wert könnte ein Problem werden. Aber wie immer: Vorzeitige Optimierung ist die Wurzel allen Übels .
Ich denke, das größere "Problem" ist, dass sich die Leute daran gewöhnen, da die Einheit normalerweise implizit wie folgt definiert ist:
Menschen werden verwirrt sein, wenn sie ein Objekt als Wert für etwas übergeben müssen, das scheinbar mit einem Einfachen beschrieben werden könnte
int
, wenn sie nicht mit Einheitensystemen vertraut sind.quelle
int
... beschrieben werden könnte." Guter Fang.Im Gegensatz zur Antwort von Null kann das Definieren eines Typs für eine "Einheit" von Vorteil sein, wenn eine Ganzzahl nicht ausreicht, um die Messung zu beschreiben. Beispielsweise wird das Gewicht häufig in mehreren Einheiten innerhalb desselben Messsystems gemessen. Denken Sie an "Pfund" und "Unzen" oder "Kilogramm" und "Gramm".
Wenn Sie eine detailliertere Messebene benötigen, ist es hilfreich, einen Typ für die Einheit zu definieren:
Für etwas wie "Alter" empfehle ich, das zur Laufzeit basierend auf dem Geburtsdatum der Person zu berechnen:
quelle
Was Sie suchen, nennt man markierte Typen . Sie sind eine Art zu sagen, "das ist eine ganze Zahl, die das Alter darstellt", während "das ist auch eine ganze Zahl, aber es stellt das Gewicht dar" und "Sie können nicht eins dem anderen zuordnen". Beachten Sie, dass dies weiter geht als physikalische Einheiten wie Meter oder Kilogramm: Ich habe in meinem Programm möglicherweise "Personenhöhen" und "Entfernungen zwischen Punkten auf einer Karte", die beide in Metern gemessen, aber nicht miteinander kompatibel sind, seitdem ich ihnen eine zugewiesen habe der andere macht aus Sicht der Geschäftslogik keinen Sinn.
Einige Sprachen, wie Scala, unterstützen ganz einfach Typen mit Tags (siehe den obigen Link). In anderen Fällen können Sie eigene Wrapper-Klassen erstellen, dies ist jedoch weniger praktisch.
Eine Validierung, z. B. die Überprüfung, ob die Größe einer Person "angemessen" ist, ist ein weiteres Problem. Sie können diesen Code in Ihre
Adult
Klasse (Konstruktor oder Setter) oder in Ihre mit Tags versehenen Typ- / Wrapper-Klassen einfügen . In gewisser Weise können eingebaute Klassen eine solche Rolle übernehmenURL
oderUUID
übernehmen (unter anderem, indem sie Dienstprogrammmethoden bereitstellen).Ob die Verwendung von Tag-Typen oder Wrapper-Klassen tatsächlich zur Verbesserung des Codes beiträgt, hängt von mehreren Faktoren ab. Wenn Ihre Objekte einfach sind und nur wenige Felder enthalten, ist das Risiko, sie falsch zuzuweisen, gering und der zusätzliche Code, der für die Verwendung markierter Typen erforderlich ist, lohnt sich möglicherweise nicht. In komplexen Systemen mit komplexen Strukturen und vielen Feldern (insbesondere wenn viele von ihnen denselben primitiven Typ haben) kann dies tatsächlich hilfreich sein.
In dem Code, den ich schreibe, erstelle ich häufig Wrapper-Klassen, wenn ich Maps umgebe. Typen wie
Map<String, String>
sind für sich genommen sehr undurchsichtig, daherNameToAddress
hilft es sehr, sie in Klassen mit aussagekräftigen Namen wie einzuhüllen. Natürlich können Sie mit markierten Typen schreibenMap<Name, Address>
und benötigen nicht den Wrapper für die gesamte Karte.Für einfache Typen wie Strings oder Integer habe ich jedoch festgestellt, dass Wrapper-Klassen (in Java) zu lästig sind. Die normale Geschäftslogik war nicht so schlecht, aber es gab eine Reihe von Problemen bei der Serialisierung dieser Typen zu JSON, der Zuordnung zu DB-Objekten usw. Sie können Zuordnungen und Hooks für alle großen Frameworks schreiben (z. B. Jackson und Spring Data). Die zusätzliche Arbeit und Wartung, die mit diesem Code verbunden ist, gleicht jedoch alles aus, was Sie durch die Verwendung dieser Wrapper gewinnen. Natürlich kann YMMV und in einem anderen System das Gleichgewicht unterschiedlich sein.
quelle