it-swarm.com.de

Sind Einzelzeichenkonstanten besser als Literale?

Ich bin kürzlich auf eine Klasse gestoßen, die so ziemlich jedes einzelne Zeichen als Konstante bereitstellt. alles von COMMA bis BRACKET_OPEN. Ich frage mich, ob dies notwendig war. Ich habe ein "Artikel" gelesen, was darauf hindeutet, dass es hilfreich sein kann, Einzelzeichenliterale in Konstanten zu ziehen. Ich bin also skeptisch.

Die Hauptattraktivität der Verwendung von Konstanten besteht darin, dass sie die Wartung minimieren, wenn eine Änderung erforderlich ist. Aber wann werden wir ein anderes Symbol als ',' verwenden, um ein Komma darzustellen?

Der einzige Grund, warum ich Konstanten anstelle von Literalen verwende, besteht darin, den Code besser lesbar zu machen. Aber ist city + CharacterClass.COMMA + state (zum Beispiel) wirklich besser lesbar als city + ',' + state?

Für mich überwiegen die Nachteile die Vorteile, hauptsächlich, dass Sie eine andere Klasse und einen anderen Import einführen. Und ich glaube an weniger Code, wo es möglich ist. Ich frage mich also, wie der allgemeine Konsens hier ist.

128
Austin Day

Tautologie :

Wenn Sie den ersten Satz der Frage lesen, ist es sehr klar, dass es bei dieser Frage nicht um geeignete Verwendungen wie geht. Wenn man magische Zahlen eliminiert, geht es bestenfalls um schreckliche, sinnlose Konsistenz. Welches ist, was diese Antwort anspricht

Der gesunde Menschenverstand sagt Ihnen, dass const char UPPER_CASE_A = 'A'; Oder const char A = 'A' Ihrem System nur Wartung und Komplexität hinzufügt. const char STATUS_CODE.ARRIVED = 'A' Ist ein anderer Fall.

Konstanten sollen Dinge darstellen, die zur Laufzeit unveränderlich sind, aber zur Kompilierungszeit möglicherweise in Zukunft geändert werden müssen. Wann würde const char A = Alles andere als A korrekt gleichsetzen?

Wenn Sie public static final char COLON = ':' In Java Code) sehen, suchen Sie denjenigen, der das geschrieben hat, und brechen Sie die Tastaturen. Wenn sich die Darstellung für COLON jemals von : Ändert. Sie werden einen Wartungsalptraum haben.

Verschleierung:

Was passiert, wenn jemand es in COLON = '-' Ändert, weil dort, wo er es verwendet, stattdessen überall ein - Benötigt wird? Schreiben Sie Unit-Tests, die im Grunde genommen assertThat(':' == COLON) für jede einzelne const Referenz angeben, um sicherzustellen, dass sie nicht geändert werden? Nur um jemanden den Test reparieren zu lassen , wenn er ihn ändert?

Wenn jemand tatsächlich argumentiert, dass public static final String EMPTY_STRING = ""; Nützlich und nützlich ist, haben Sie nur sein Wissen qualifiziert und sie bei allem anderen sicher ignoriert.

Wenn jedes druckbare Zeichen mit einer benannten Version verfügbar ist, zeigt dies nur, dass jeder, der es getan hat, nicht qualifiziert ist, unbeaufsichtigt Code zu schreiben.

Zusammenhalt:

Es senkt auch künstlich den Zusammenhalt, weil es Dinge von den Dingen wegbewegt, die sie benutzen und mit ihnen verwandt sind.

In der Computerprogrammierung bezieht sich Kohäsion auf den Grad, in dem die Elemente eines Moduls zusammengehören. Somit misst die Kohäsion die Stärke der Beziehung zwischen Teilen der Funktionalität innerhalb eines bestimmten Moduls. Beispielsweise ist in stark kohäsiven Systemen die Funktionalität stark miteinander verbunden.

Kupplung:

Außerdem werden viele nicht verwandte Klassen miteinander verbunden, da sie alle auf Dateien verweisen, die nicht wirklich mit dem zusammenhängen, was sie tun.

Eine enge Kopplung liegt vor, wenn eine Gruppe von Klassen stark voneinander abhängig ist. Dieses Szenario tritt auf, wenn eine Klasse zu viele Aufgaben übernimmt oder wenn ein Anliegen auf mehrere Klassen verteilt ist, anstatt eine eigene Klasse zu haben.

Wenn Sie einen besseren Namen wie DELIMITER = ',' Verwenden würden, hätten Sie immer noch das gleiche Problem, da der Name generisch ist und keine Semantik enthält. Das Neuzuweisen des Werts hilft nicht mehr bei der Durchführung einer Auswirkungsanalyse als das Suchen und Ersetzen des Literals ','. Denn was ist ein Code, der es verwendet und den , Benötigt, und ein anderer Code verwendet, aber jetzt ; Benötigt? Müssen immer noch jede Verwendung manuell betrachten und ändern.

In der Wildnis:

Ich habe kürzlich eine 1,000,000+ LOC - Anwendung überarbeitet, die 18 Jahre alt war. Es hatte Dinge wie public static final COMMA = SPACE + "," + SPACE;. Das ist in keiner Weise besser, als " , " Einfügen, wo es benötigt wird.

Wenn Sie die Lesbarkeit argumentieren möchten, müssen Sie lernen, wie Sie Ihre IDE) für die Anzeige von whitespace konfigurieren Zeichen, bei denen Sie sie sehen können oder was auch immer, das ist nur ein äußerst fauler Grund, Entropie in ein System einzuführen.

Es hatte auch , Mehrfach mit mehreren Rechtschreibfehlern des Wortes COMMA in mehreren Paketen und Klassen definiert. Mit Verweisen auf alle Variationen, die im Code miteinander vermischt sind. Es war ein wahrer Albtraum, etwas zu reparieren , ohne etwas völlig anderes zu zerbrechen.

Wie beim Alphabet gab es mehrere UPPER_CASE_A, A, UPPER_A, A_UPPER, Die die meiste Zeit gleich A waren aber in einigen Fällen nicht . Für fast jeden Charakter, aber nicht für alle Charaktere.

Und aus den Bearbeitungsverläufen ging nicht hervor, dass eine einzige davon in den letzten 18 Jahren jemals bearbeitet oder geändert wurde. Aus dem Grund, der jetzt offensichtlich sein sollte, würde es viel zu viele Dinge zerstören, die nicht nachvollziehbar waren, sodass Sie eine neue Variable haben Namen, die auf dasselbe verweisen, das aus demselben Grund niemals geändert werden kann.

In keiner vernünftigen Realität können Sie argumentieren, dass diese Praxis nichts anderes tut, als mit maximaler Entropie zu beginnen.

Ich überarbeitete all dieses Durcheinander und stellte fest, dass alle Tautologien und die neuen College-Einstellungen viel produktiver waren, weil sie nicht durch mehrere Indirektionsebenen suchen mussten, worauf diese const - Referenzen tatsächlich hinwiesen, weil sie es nicht waren zuverlässig in dem, was sie genannt wurden und was sie enthielten.

182
user7519

Die Hauptattraktivität der Verwendung von Konstanten besteht darin, dass sie die Wartung minimieren, wenn eine Änderung erforderlich ist.

ABSOLUT NICHT. Dies ist überhaupt nicht der Grund, Konstanten zu verwenden, weil Konstanten ändern sich per Definition nicht. Wenn sich eine Konstante jemals ändert dann war es keine Konstante, oder?

Der Reiz, Konstanten zu verwenden, hat überhaupt nichts mit Änderungsmanagement zu tun und alles damit, Programme für das Schreiben, Verstehen und Verwalten durch Menschen zugänglich zu machen. Wenn ich überall in meinem Programm wissen möchte, wo ein Doppelpunkt als URL-Trennzeichen verwendet wird, kann ich das sehr leicht wissen, wenn ich die Disziplin habe, einen konstanten URLSeparator zu definieren, und kann das überhaupt nicht leicht wissen, wenn ich danach suchen muss : und erhalte jede einzelne Stelle im Code, an der : wird verwendet, um eine Basisklasse oder ein ?: Operator oder was auch immer.

Ich bin völlig anderer Meinung als die anderen Antworten, die besagen, dass dies eine sinnlose Zeitverschwendung ist. Benannte Konstanten fügen einem Programm Bedeutung hinzu, und diese Semantik kann sowohl von Menschen als auch von Maschinen verwendet werden, um ein Programm besser zu verstehen und es effektiver zu pflegen.

Der Trick dabei ist nicht, Konstanten zu meiden, sondern sie mit ihren semantischen Eigenschaften und nicht mit ihren syntaktischen Eigenschaften zu benennen. Wofür wird die Konstante verwendet? Nennen Sie es nicht Comma, es sei denn, die Geschäftsdomäne Ihres Programms ist Typografie, Parsing in englischer Sprache oder dergleichen. Nennen Sie es ListSeparator oder so etwas, um die Semantik der Sache klar zu machen.

145
Eric Lippert

Nein, das ist dumm.

Was nicht unbedingt dumm ist, ist, solche Dinge aus Lokalisierungsgründen in benannte Labels zu ziehen. Zum Beispiel ist das Tausendertrennzeichen ist ein Komma in Amerika (1.000.000), aber nicht ein Komma in anderen Regionen. Wenn Sie dies in eine benannte Bezeichnung (mit einem geeigneten Namen ohne Komma) ziehen, kann der Programmierer diese Details ignorieren/abstrahieren.

Aber eine Konstante zu machen, weil "magische Saiten schlecht sind", ist nur Frachtkult.

61
Telastyn

Es gibt einige Zeichen, die mehrdeutig sein können oder für verschiedene Zwecke verwendet werden. Zum Beispiel verwenden wir '-' als Bindestrich, Minuszeichen oder sogar als Bindestrich. Sie können separate Namen erstellen als:

static const wchar_t HYPHEN = '-';
static const wchar_t MINUS = '-';
static const wchar_t EM_DASH = '-';

Später können Sie Ihren Code so ändern, dass er eindeutig ist, indem Sie ihn neu definieren als:

static const wchar_t HYPHEN = '-';
static const wchar_t MINUS = '\u2122';
static const wchar_t EM_DASH = '\u2014';

Dies könnte ein Grund sein, warum Sie berücksichtigen Konstanten für bestimmte einzelne Zeichen definieren würden. jedoch, die Anzahl der Zeichen, die auf diese Weise mehrdeutig sind, ist gering. Es scheint höchstens, dass Sie es nur für diese tun würden. Ich würde auch argumentieren, dass Sie warten könnten, bis Sie tatsächlich die mehrdeutigen Zeichen unterscheiden müssen, bevor Sie den Code auf diese Weise faktorisieren.

Da typografische Konventionen je nach Sprache und Region variieren können, ist es wahrscheinlich besser, solche mehrdeutigen Satzzeichen aus einer Übersetzungstabelle zu laden.

29
Adrian McCarthy

Eine Konstante muss Bedeutung hinzufügen.

Die Definition von COMMA als Komma fügt keine Bedeutung hinzu, da wir wissen, dass ein Komma ein Komma ist. Stattdessen zerstören wir die Bedeutung, weil COMMA jetzt möglicherweise kein Komma mehr ist.

Wenn Sie ein Komma für einen Zweck verwenden und eine benannte Konstante verwenden möchten, benennen Sie sie nach ihrem Zweck. Beispiel:

  • city + CharacterClass.COMMA + state = Schlecht
  • city + CITY_STATE_DELIMITER + state = Gut

Verwenden Sie Funktionen zum Formatieren

Ich persönlich bevorzuge FormatCityState(city, state) und kümmere mich nicht darum, wie der Körper dieser Funktion aussieht, solange er kurz ist und die Testfälle besteht.

22
Peter

Die Idee, dass eine konstante COMMA besser ist als ',' Oder ",", Ist ziemlich einfach zu entlarven. Sicher, es gibt Fälle, in denen es sinnvoll ist, zum Beispiel final String QUOTE = "\""; Zu machen, was die Lesbarkeit ohne alle Schrägstriche erheblich beeinträchtigt, aber Sprachsteuerungszeichen wie \' Und " Ich habe sie nicht als sehr nützlich empfunden.

Die Verwendung von final String COMMA = "," Ist nicht nur eine schlechte Form, sondern auch gefährlich! Wenn jemand das Trennzeichen von "," In ";" Ändern möchte, ändert er möglicherweise die Konstantendatei in COMMA = ";", Weil dies für ihn schneller ist und einfach funktioniert. Abgesehen davon, dass alle anderen Dinge, die COMMA jetzt verwendet haben, jetzt auch Semikolons sind, einschließlich Dinge, die an externe Verbraucher gesendet werden. Es besteht also alle Ihre Tests (da der gesamte Marshalling- und Unmarshalling-Code ebenfalls COMMA verwendet hat), aber externe Tests schlagen fehl.

Was nützlich ist, ist ihnen nützliche Namen zu geben. Und ja, manchmal haben mehrere Konstanten den gleichen Inhalt, aber unterschiedliche Namen. Zum Beispiel final String LIST_SEPARATOR = ",".

Ihre Frage lautet also "Sind einzelne Zeichenkonstanten besser als Literale" und die Antwort lautet eindeutig "Nein", das sind sie nicht. Aber noch besser als beide ist ein eng umrissener Variablenname, der explizit angibt, wozu er dient. Sicher, Sie werden ein paar zusätzliche Bytes für diese zusätzlichen Referenzen ausgeben (vorausgesetzt, sie werden nicht für Sie kompiliert, was sie wahrscheinlich tun werden), aber bei der langfristigen Wartung, bei der die meisten Kosten einer Anwendung anfallen, sind sie es sind die Zeit wert zu machen.

17
corsiKa

Ich habe einige Arbeiten zum Schreiben von Lexern und Parsern durchgeführt und ganzzahlige Konstanten verwendet, um Terminals darzustellen. Einzelzeichen-Terminals hatten der Einfachheit halber zufällig den Code ASCII) als numerischen Wert, aber der Code hätte auch etwas ganz anderes sein können. Ich hätte also einen T_COMMA, dem der ASCII zugewiesen wurde -code für ',' als konstanten Wert. Es gab jedoch auch Konstanten für Nicht-Terminals, denen Ganzzahlen über dem Satz ASCII) zugewiesen wurden. Bei der Betrachtung von Parser-Generatoren wie yacc oder bison oder Parsern Mit diesen Tools geschrieben, hatte ich den Eindruck, dass es im Grunde alle so gemacht haben.

Während ich, wie alle anderen auch, es für sinnlos halte, Konstanten für den ausdrücklichen Zweck zu definieren, die Konstanten anstelle der Literale in Ihrem Code zu verwenden, gibt es meiner Meinung nach Edge-Fälle (z. B. Parser), in denen Sie möglicherweise auf Code stoßen, mit dem Sie durchsetzt sind Konstanten wie Sie beschreiben. Beachten Sie, dass im Parser-Fall die Konstanten nicht nur zur Darstellung von Zeichenliteralen dienen. Sie stellen Entitäten dar, die möglicherweise passieren Zeichenliterale sind.

Ich kann mir einige weitere Einzelfälle vorstellen, in denen es möglicherweise sinnvoll ist, Konstanten anstelle der entsprechenden Literale zu verwenden. Beispielsweise können Sie NEWLINE als das Literal '\ n' auf einer Unix-Box definieren, aber '\ r\n' oder '\ n\r', wenn Sie sich unter Windows oder Mac-Box befinden. Gleiches gilt für das Parsen von Dateien, die Tabellendaten darstellen. Sie können die Konstanten FIELDSEPARATOR und RECORDSEPARATOR definieren. In diesen Fällen definieren Sie tatsächlich eine Konstante, um ein Zeichen darzustellen, das eine bestimmte Funktion erfüllt. Wenn Sie ein unerfahrener Programmierer wären, würden Sie Ihre Feldtrenner-Konstante möglicherweise COMMA nennen, ohne zu wissen, dass Sie sie FIELDSEPARATOR hätten nennen sollen, und wenn Sie erkennen, dass der Code in Produktion ist und Sie sich auf dem nächsten befinden Projekt, so dass die falsch benannte Konstante im Code bleibt, damit jemand sie später finden und den Kopf schütteln kann.

Schließlich ist die von Ihnen beschriebene Praxis möglicherweise in einigen Fällen sinnvoll, in denen Sie Code schreiben, um Daten zu verarbeiten, die in einer bestimmten Zeichenkodierung codiert sind, z. B. iso-8859-1, aber erwarten, dass sich die Codierung später ändert. In einem solchen Fall wäre es natürlich viel sinnvoller, Lokalisierungs- oder Codierungs- und Decodierungsbibliotheken zu verwenden, aber wenn Sie aus irgendeinem Grund eine solche Bibliothek nicht verwenden könnten, um Codierungsprobleme für Sie zu behandeln, verwenden Sie nur Konstanten Möglicherweise müssen Sie in einer einzigen Datei neu definieren, anstatt fest codierte Literale, die über den gesamten Quellcode verteilt sind.

Zu dem Artikel, auf den Sie verlinkt haben: Ich glaube nicht, dass er versucht, Zeichenliterale durch Konstanten zu ersetzen. Ich denke, es wird versucht, eine Methode zu veranschaulichen, mit der Schnittstellen verwendet werden, um Konstanten in andere Teile Ihrer Codebasis zu ziehen. Die Beispielkonstanten, die verwendet werden, um dies zu veranschaulichen, sind sehr schlecht gewählt, aber ich denke nicht, dass sie in irgendeiner Weise von Bedeutung sind.

3
Pascal

Zusätzlich zu all den guten Antworten hier möchte ich als Denkanstoß hinzufügen, dass es bei guter Programmierung darum geht, geeignete Abstraktionen bereitzustellen. das kann von Ihnen und vielleicht von anderen aufgebaut werden, ohne dass Sie denselben Code immer wieder wiederholen müssen.

Gute Abstraktionen machen den Code einerseits benutzerfreundlich und andererseits einfach zu pflegen.

Ich stimme voll und ganz dem DELIMITER=':' an und für sich ist eine schlechte Abstraktion und nur gerade besser als COLON=':' (da letzterer völlig verarmt ist).

Eine gute Abstraktion mit Zeichenfolgen und Trennzeichen würde eine Möglichkeit beinhalten, ein oder mehrere einzelne Inhaltselemente in die Zeichenfolge zu packen und sie in erster Linie auch aus der gepackten Zeichenfolge zu entpacken, bevor Sie den Trennzeichen angeben. Eine solche Abstraktion würde als Konzept gebündelt, in den meisten Sprachen als Klasse; Zum Beispiel, damit seine Verwendung praktisch selbstdokumentierend ist, indem Sie nach allen Stellen suchen können, an denen diese Klasse verwendet wird, und sich sicher sein können, was der Programmierer hinsichtlich des Formats der gepackten Zeichenfolgen in jedem Fall beabsichtigt, in dem eine gewisse Abstraktion verwendet wird.

Sobald eine solche Abstraktion bereitgestellt ist, wäre es einfach zu verwenden, ohne jemals den Wert von DELIMITER oder COLON abfragen zu müssen, und das Ändern der Implementierungsdetails wäre im Allgemeinen auf das beschränkt Implementierung. Kurz gesagt, diese Konstanten sollten wirklich Implementierungsdetails sein, die in einer geeigneten Abstraktion verborgen sind.

Die Hauptattraktivität der Verwendung von Konstanten besteht darin, dass sie die Wartung minimieren, wenn eine Änderung erforderlich ist.

Gute Abstraktionen, bei denen es sich in der Regel um Zusammensetzungen mehrerer verwandter Funktionen handelt, können die Wartung besser minimieren. Erstens trennen sie den Anbieter klar von den Verbrauchern. Zweitens verbergen sie die Implementierungsdetails und bieten stattdessen direkt nützliche Funktionen. Drittens dokumentieren sie auf hohem Niveau, wann und wo sie verwendet werden.

3
Erik Eidt

Ich habe einmal gesehen, dass solche Konstanten effektiv verwendet werden, um einer vorhandenen API oder einem vorhandenen Dokument zu entsprechen. Ich habe Symbole wie COMMA gesehen, die verwendet wurden, weil eine bestimmte Software direkt mit einem Parser verbunden war, der COMMA als Tag in einem abstrakten Syntaxbaum verwendete. Ich habe auch gesehen, dass es einer formalen Spezifikation entspricht. In formalen Spezifikationen werden manchmal Symbole wie COMMA anstelle von ',' angezeigt, weil sie so klar wie möglich sein sollen.

In beiden Fällen trägt die Verwendung eines benannten Symbols wie COMMA dazu bei, einem ansonsten nicht zusammenhängenden Produkt Zusammenhalt zu verleihen. Dieser Wert kann oft die Kosten für übermäßig ausführliche Notationen überwiegen.

2
Cort Ammon

Beachten Sie, dass Sie versuchen, eine Liste zu erstellen.

Refactor es also als: String makeList(String[] items)

Mit anderen Worten, berücksichtigen Sie die Logik anstelle der Daten .
Sprachen können sich in der Darstellung von Listen unterscheiden, aber Kommas sind immer Kommas (das ist eine Tautologie). Wenn sich also die Sprache ändert, hilft es Ihnen nicht, das Komma zu ändern - aber das wird es.

2
user541686

Wenn dies eine Klasse war, die als Teil einer Anwendung von Ihrem Entwicklerkollegen geschrieben wurde, ist dies mit ziemlicher Sicherheit eine schlechte Idee. Wie andere bereits betont haben, ist es sinnvoll, Konstanten wie SEPARATOR = ',' wo Sie den Wert und die Konstante ändern können, ist immer noch sinnvoll, aber viel weniger Konstanten, deren Name nur ihren Wert beschreibt.

Es gibt jedoch mindestens zwei Fälle, in denen es sinnvoll ist, Konstanten zu deklarieren, deren Name genau ihren Inhalt beschreibt, und in denen Sie den Wert nicht ändern können, ohne den Namen der Konstante entsprechend zu ändern:

  • Mathematische oder physikalische Konstanten, z. PI = 3.14159. Hier besteht die Rolle der Konstante darin, als Mnemonik zu fungieren, da der symbolische Name PI viel kürzer und lesbarer ist als der Wert, den er darstellt.
  • Vollständige Liste von Symbolen in einem Parser oder Tasten auf einer Tastatur. Es kann sogar sinnvoll sein, eine Liste von Konstanten mit den meisten oder allen Unicode-Zeichen zu haben. Und hier kann Ihr Fall liegen. Einige Zeichen wie A sind offensichtlich und klar erkennbar. Aber können Sie leicht sagen А und A auseinander? Der erste ist der kyrillische Buchstabe А , während der letztere der lateinische Buchstabe A ist. . Es handelt sich um verschiedene Buchstaben, die durch verschiedene Unicode-Codepunkte dargestellt werden, obwohl sie grafisch fast identisch sind. Ich hätte lieber Konstanten CYRILLIC_CAPITAL_A und LATIN_CAPITAL_A in meinem Code als zwei fast identisch aussehende Zeichen. Dies ist natürlich sinnlos, wenn Sie wissen, dass Sie nur mit ASCII Zeichen, die kein Kyrillisch enthalten) arbeiten. Ebenso: Ich verwende das lateinische Alphabet täglich, wenn ich also ein Programm schreibe Wenn Sie ein chinesisches Schriftzeichen benötigen, würde ich wahrscheinlich lieber eine Konstante verwenden, als ein Zeichen einzufügen, das ich nicht verstehe. Für jemanden, der täglich chinesische Schriftzeichen verwendet, kann ein chinesisches Schriftzeichen offensichtlich sein, ein lateinisches jedoch einfacher Wie Sie sehen, hängt dies vom Kontext ab. Dennoch kann eine Bibliothek symbolische Konstanten für alle Zeichen enthalten, da die Autoren nicht im Voraus wissen können, wie und welche Zeichen die Bibliothek verwendet werden soll Möglicherweise sind Konstanten erforderlich, um die Lesbarkeit in einer bestimmten Anwendung zu verbessern.

Solche Fälle werden jedoch normalerweise von Systemklassen oder Spezialbibliotheken behandelt, und ihr Auftreten in Code, der von Anwendungsentwicklern geschrieben wurde, sollte sehr selten sein, es sei denn, Sie arbeiten an einem ganz speziellen Projekt.

0