Ich schreibe ein Programm, bei dem sowohl mit polaren als auch mit kartesischen Koordinaten gearbeitet wird.
Ist es sinnvoll, zwei verschiedene Strukturen für jede Art von Punkten zu erstellen, eine mit X
und Y
Mitgliedern und eine mit R
und Theta
Mitgliedern.
Oder ist es zu viel und es ist besser, nur eine Struktur mit first
und second
als Mitglieder zu haben.
Was ich schreibe, ist einfach und es wird sich nicht viel ändern. Aber ich bin gespannt, was aus gestalterischer Sicht besser ist.
Ich denke, die erste Option ist besser. Es scheint lesbarer zu sein und ich werde den Vorteil der Typprüfung erhalten.
Antworten:
Ich habe beide Lösungen gesehen, es ist also definitiv kontextabhängig.
Aus Gründen der Lesbarkeit ist es sehr effektiv, mehrere Strukturen zu haben, wie Sie vorschlagen. In einigen Umgebungen möchten Sie jedoch häufig Änderungen an diesen Strukturen vornehmen und dabei feststellen, dass Sie Code duplizieren, z. B. Matrix-Vektor-Operationen. Es kann frustrierend werden, wenn die jeweilige Operation in Ihrem Vektor nicht verfügbar ist, weil sie dort nicht portiert wurde.
Die extreme Lösung (auf die wir schließlich eingegangen sind) besteht darin, eine CRTP-Basisklasse mit den Funktionen get <0> () get <1> () und get <2> () zu haben, um die Elemente auf generische Weise abzurufen. Diese Funktionen werden dann in der kartesischen oder polaren Struktur definiert, die von dieser Basisklasse abgeleitet ist. Es löst alle Probleme, hat aber einen ziemlich dummen Preis: Sie müssen die Template-Metaprogrammierung erlernen. Wenn die Metaprogrammierung von Vorlagen jedoch für Ihr Projekt bereits ein faires Spiel ist, ist dies möglicherweise eine gute Übereinstimmung.
quelle
Ja, das macht sehr viel Sinn.
Der Wert einer Struktur besteht nicht nur darin, dass sie Daten unter einem handlichen Namen kapselt. Der Wert ist, dass er Ihre Absichten kodiert, sodass der Compiler Sie dabei unterstützen kann, sicherzustellen, dass Sie sie eines Tages nicht verletzen (z. B. Verwechseln eines Polarkoordinatensatzes mit einem kartesischen Koordinatensatz).
Die Leute sind schlecht darin, sich an solche verworrenen Details zu erinnern, aber gut darin, mutige, erfinderische Pläne zu entwickeln. Computer sind gut darin, Details auszunageln, und schlecht darin, kreative Pläne zu machen. Aus diesem Grund ist es immer eine gute Idee, so viel Detailpflege wie möglich auf den Computer zu verlagern.
quelle
Ja, obwohl sowohl kartesisch als auch polar (an ihrer Stelle) äußerst vernünftige Koordinatendarstellungsschemata sind, sollten sie idealerweise niemals gemischt werden (wenn Sie einen kartesischen Punkt {1,1} haben, ist dies ein ganz anderer Punkt als polar {1,1) }).
Je nach Bedarf kann es auch sinnvoll sein eine Schnittstelle Koordinaten Umsetzung mit Methoden wie
X()
,Y()
,Displacement()
undAngle()
(oder möglicherweiseRadius()
undTheta()
je nach).quelle
Letztendlich besteht das Ziel der Programmierung darin, die Transistor-Bits umzuschalten, um nützliche Arbeit zu leisten. Wenn Sie jedoch auf einem so niedrigen Niveau denken, kann dies zu einer unüberschaubaren Verrücktheit führen. Aus diesem Grund gibt es höhere Programmiersprachen, die Ihnen helfen, die Komplexität zu verbergen.
Wenn Sie nur eine Struktur mit den Elementen named
first
und erstellensecond
, haben die Namen keine Bedeutung. Sie würden sie im Wesentlichen als Speicheradressen behandeln. Das macht den Zweck der höheren Programmiersprache zunichte.Nur weil sie alle darstellbar sind,
double
bedeutet dies nicht, dass Sie sie austauschbar verwenden können. Beispielsweise ist θ ein dimensionsloser Winkel, während y Längeneinheiten hat. Da die Typen nicht logisch ersetzbar sind, sollten es zwei inkompatible Strukturen sein.Wenn Sie wirklich Tricks zur Wiederverwendung des Gedächtnisses spielen müssen - und das sollten Sie mit ziemlicher Sicherheit nicht -, können Sie einen
union
Typ in C verwenden, um Ihre Absicht zu verdeutlichen.quelle
Erstens, haben beide explizit, wie nach @ Kilian-foths ganz vernünftiger Antwort.
Ich möchte jedoch hinzufügen:
Fragen Sie: Haben Sie wirklich Operationen, die für beide generisch sind, wenn sie als Paar betrachtet werden
double
? Beachten Sie dies nicht gleichbedeutend mit der Aussage, dass Sie Vorgänge haben, die für beide in ihren eigenen Bedingungen gelten. Zum Beispiel interessiert 'plot (Coord)', obCoord
polar oder kartesisch ist. Auf der anderen Seite werden die Daten so behandelt, wie sie sind, wenn Sie in der Datei bleiben. Wenn Sie wirklich generische Operationen verfügen, erwägen die Definition entweder eine Basisklasse, oder definieren einen Konverter einstd::pair<double, double>
odertuple
oder was auch immer Sie in Ihrer Sprache haben.Ferner könnte ein Ansatz darin bestehen, einen Koordinatentyp als grundlegender und den anderen als bloße Unterstützung für Benutzer- oder externe Interaktion zu behandeln.
Sie können also sicherstellen, dass alle grundlegenden Vorgänge für codiert sind,
Cartesian
und dann die KonvertierungPolar
nach unterstützenCartesian
. Dadurch wird vermieden, dass verschiedene Versionen vieler Vorgänge implementiert werden.quelle
Eine mögliche Lösung ist, abhängig von der Sprache und wenn Sie wissen, dass beide Klassen ähnliche Methoden und Operationen haben, die einmalige Definition der Klasse und die Verwendung von Typ-Aliasen, um die Typen explizit unterschiedlich zu benennen.
Dies hat auch den Vorteil, dass Sie, solange die Klassen exakt gleich sind, nur eine beibehalten können. Sobald Sie sie ändern müssen, müssen Sie den Code nicht mehr mit ihnen ändern, da die Typen bereits verwendet wurden deutlich.
Eine weitere Option, die wiederum von der Verwendung der Klassen abhängt (wenn Sie Polymorphismus und dergleichen benötigen), ist die Verwendung der öffentlichen Vererbung für beide neuen Typen, sodass sie dieselbe öffentliche Schnittstelle haben wie der gemeinsame Typ, den sie beide darstellen. Dies ermöglicht auch eine getrennte Entwicklung der Typen.
quelle
Ich halte es in diesem Fall für eine schlechte Idee, dieselben Mitgliedsnamen zu haben, da der Code dadurch fehleranfälliger wird.
Stellen Sie sich das Szenario vor: Sie haben ein paar kartesische Punkte: pntA und pntB. Dann entscheiden Sie sich aus irgendeinem Grund, dass sie besser in Polarkoordinaten dargestellt werden sollen, und ändern die Deklaration und den Konstruktor.
Wenn alle Ihre Operationen nur Methodenaufrufe wären wie:
dann geht es dir gut Aber was ist, wenn Sie die Mitglieder explizit verwendet haben? Vergleichen Sie
Im ersten Fall wird der Code nicht kompiliert. Sie sehen den Fehler sofort und können ihn beheben. Wenn Sie jedoch dieselben Mitgliedsnamen haben, liegt der Fehler nur auf der logischen Ebene und ist viel schwerer zu erkennen.
Wenn Sie in einer nicht objektorientierten Sprache schreiben, ist es noch einfacher, eine falsche Struktur an die Funktion zu übergeben. Was hindert Sie daran, den folgenden Code zu schreiben?
Verschiedene Datentypen ermöglichen es Ihnen andererseits, den Fehler während der Kompilierung zu finden.
quelle