単一文字の定数はリテラルよりも優れていますか?


127

私は最近、ほとんどすべての単一文字を定数として提供するクラスに遭遇しました。からCOMMAまでのすべてBRACKET_OPEN。これが必要かどうか疑問に思います。私は、単一文字のリテラルを定数に取り込むことが役立つと示唆する「記事」を読みました。だから、私は懐疑的です。

定数を使用する主な魅力は、変更が必要なときにメンテナンスを最小限に抑えることです。しかし、いつコンマを表すために「、」とは異なるシンボルを使用し始めますか?

リテラルの代わりに定数を使用する唯一の理由は、コードを読みやすくすることです。しかし、city + CharacterClass.COMMA + state(たとえば)本当に読みやすいですcity + ',' + stateか?

私にとって、主にあなたが別のクラスと別のインポートを導入するという短所は長所を上回ります。そして、可能な限り少ないコードを信じています。だから、私は一般的なコンセンサスがここにあるのだろうかと思っています。



33
うーん...多分異なるロケールに役立つかもしれませんか?たとえば、一部の言語では、英語の標準(または見栄えの良いand )の代わりに、引用符としてguillements(角引用符、«および»)を使用します。それとは別に、魔法のキャラクターのセットのように聞こえます。呼び出されたとの2つのインスタンスを仮定すると、がである可能性がありますが、である可能性があります。"CharacterClassenglishCharsfrenchCharsenglishChars.LEFT_QUOTEfrenchChars.LEFT_QUOTE«
ジャスティンタイム

4
カンマには多くの異なるバリアントがあります:en.wikipedia.org/wiki/Comma#Comma_variants-特にソースコードをutf-8としてエンコードできる場合、これはそれほど愚かなアイデアではないでしょう。
アーロンホール

21
あなたの場合、それは変数「番号」を呼び出すようなものです。定数はDELIMITERと呼ばれるべきです。またはそれは= "{0}、{1}" CITY_STATEなければならない
the_lotus

13
リンクした記事は非常にひどいものです。定数は、そのようなバケツに投げ込まれてなりませ。コンテキストがあるクラスにそれらを置きます。本質的に、定数を持つクラスは、定数が使用されるコンテキストを提供します。たとえば、JavaのFile.separator。このクラスは、セパレータのタイプを示します。クラスに名前を付けるConstsConstants、コンテキストを提供しないと、定数を正しく使用するのが難しくなります。

回答:


183

トートロジー

質問の最初の文を読んだ場合、この質問は マジックナンバーの削除 などの適切な使用に関するものではなく、せいぜいひどい愚かな愚かな一貫性に関するものであることは非常に明白です。これはこの答えが対処するものです

常識はあなたにそれを伝えるconst char UPPER_CASE_A = 'A';か、const char A = 'A'お使いのシステムにメンテナンスや複雑さが、何も追加しません。const char STATUS_CODE.ARRIVED = 'A'別のケースです。

定数は、実行時には不変なものを表すものと想定されていますが、将来コンパイル時に変更する必要がある場合があります。いつconst char A =以外に正しく等しくなるのでしょうAか?

public static final char COLON = ':'Javaコードで見た場合、それを書いた人を見つけてキーボードを壊してください。あなたCOLONからの表現がこれまでに変更された:場合、メンテナンスの悪夢が生じます。

難読化:

誰かがそれをCOLON = '-'使用している-場所でどこでも代わりにそれを必要とするためにそれを変更するとどうなりますか?基本的assertThat(':' == COLON)にすべての単一のconst参照に対して、それらが変更されないことを確認するように言う単体テストを書くつもりですか?テストを変更したときに誰かにテストを修正してもらうだけですか?

誰かがそれpublic static final String EMPTY_STRING = "";が有用で有益であると実際に主張する場合、あなたは彼らの知識を修飾し、他のすべてについてそれらを安全に無視します。

名前付きバージョンですべての印刷可能な文字を使用できるようにすることは、誰がそれを行ったとしても、監視なしでコードを書く資格がないことを示すだけです。

凝集:

また、人工的に凝集力を低下させます。なぜなら、それを使用し、関連しているものから物を遠ざけるからです。

コンピュータプログラミングでは、結合とは、モジュールの要素がどの程度一緒に属しているかを指します。したがって、凝集度は、特定のモジュール内の機能の断片間の関係の強さを測定します。たとえば、高度に凝集したシステムでは、機能は強く関連しています。

カップリング:

また、関係のない多くのクラスも一緒に結合されます。それらはすべて、実際に実行する内容に実際には関係のないファイルを参照するためです。

密結合とは、クラスのグループが互いに強く依存している場合です。このシナリオは、クラスが多くの責任を引き受ける場合、または1つの懸念が独自のクラスを持つのではなく、多くのクラスに広がっている場合に発生します。

あなたが使用した場合より良い名前のようなDELIMITER = ','名前が総称で、何のセマンティックを運ばないので、あなたはまだ、同じ問題を抱えているだろう。値を再割り当てすることは、リテラルを検索して置換することよりも、影響分析を行うのに役立ちます','。いくつかのコードはそれを使用し、,他のコードは使用する必要がありますが、;今は必要ですか?それでも、すべての使用を手動で確認して変更する必要があります。

野生で:

私は最近、1,000,000+ LOC18歳のアプリケーションをリファクタリングしました。のようなものがありましたpublic static final COMMA = SPACE + "," + SPACE;。それは、" , "それが必要な場所を単にインライン化するよりも良い方法ではありません。

読みやすさを議論したい場合は、whitespace文字を表示できるようにIDEを構成することを学ぶ必要があります。これは、エントロピーをシステムに導入する非常に怠zyな理由です。

また、複数のパッケージおよびクラスの,単語のスペルミスを複数回定義していたCOMMA。コード内で混在するすべてのバリエーションへの参照。完全に無関係なものを壊すことなく、何かを修正しようとすることは悪夢にほかなりません。

アルファベットと同じ、複数のがありましたUPPER_CASE_AAUPPER_AA_UPPERほとんどの時間に等しいだったことA が、いくつかのケースではありませんでした。ほとんどすべての文字についてですが、すべての文字についてではありません。

そして、編集履歴から、これらの単一のものが18年間にわたって編集または変更されたようには見えませんでした、今明らかな理由のために、追跡できないものがあまりにも多くの方法で壊れてしまうため、新しい変数同じ理由で変更できない同じものを指す名前。

健全な現実では、このプラクティスは何もせずに最大エントロピーから始めると主張することはできません。

私はこの混乱をすべてリファクタリングし、すべてのトートロジーをインライン化し、新しい大学の採用は、これらのconst参照が実際に指し示していた複数のレベルの間接参照を追いかける必要がないため、はるかに生産的でしたvs含まれるもの。


112
たぶん、あなたは反例を追加する必要const char DELIMITER = ':'があります:実際に役に立つでしょう。
ベルギ

115
EMPTY_STRING有益な議論をいくつかします。(1)のEMPTY_STRINGすべての使用を見つけるよりも、ファイル内のすべての使用をはるかに簡単に見つけることができます""。(2)EMPTY_STRING開発者がその文字列を空にすることを意図していたこと、そしてそれが誤って編集されたり、後で提供される文字列のプレースホルダーではないことを確信しています。さて、あなたは、私がこの議論をすることによって、あなたが私の知識を修飾し、永久に私を安全に無視できると主張します。それでは、私の知識をどのように認定しますか?そして、私のアドバイスを永遠に無視するつもりですか?どちらの方法でも問題はありません。
エリックリッパー

39
@immibis:変更を管理するという文脈において、これらのことを有用だと考えるのをやめることができます。それらは定数です。彼らは変わりません。それらがコードの意味論を検索して理解する人間の文脈で役に立つと考えてください。何かがキーと値のペアの区切り文字であることを知ることは、それがコロンであることを知ることよりもはるかに便利です。それは、構文ではなく、プログラムの関心の意味領域に関する事実です。
エリックリッパー

15
@EricLippert:私はちょっとということのみを保証することを指摘し、ここで他人のポイント見ているconst私はのセマンティックな意味があることあなたに同意んが、提供しては、それが(コンパイル後に)実行時に変更されないということですがconstあります変更管理ツールとしての使用よりもはるかに重要です。const EARLIEST_OS_SUPPORTEDとはいえ、私は確かに、意味的に一貫しているだけでなく、プログラムが進化し、古い不要なものが削除されるにつれて時間とともに変化するものを想像できます。
ロバートハーベイ

16
@DanielJour:したがって、これはの3番目の引数ですEMPTY_STRING。適切に設計されたIDEにより、このエンティティを構文的にではなく、象徴的に扱うことができるツールが表示されます。これを4番目の引数に一般化します。IDEの下にあるコード分析ツールのライブラリにより、シンボルレベルでのコードの正確性の高度なプログラム分析が可能になる場合があります。文字通り40年前に書かれたツールよりも高度なツールを活用したい開発者は、高度なツールの報酬を得るために、習慣を少し変更するだけで済みます。
エリックリッパー

145

定数を使用する主な魅力は、変更が必要なときにメンテナンスを最小限に抑えることです。

絶対違う。定数は定義により変化しないため、これは定数を使用する理由はありません。定数が変更された場合、それは定数ではありませんでしたか?

定数を使用することの魅力は、変更管理や、プログラムを人々が記述、理解、および保守しやすくすることとは関係ありません。コロンがURLセパレータとして使用されているプログラムのすべての場所を知りたい場合、定数URLSeparatorを定義する規律があれば簡単に知ることができます。:そして:、基本クラス、?:演算子、その他を示すために使用されるコード内のすべての場所を取得します。

私はこれが時間の無駄な無駄だと述べる他の答えには完全に反対します。名前付き定数はプログラムに意味を追加します。これらのセマンティクスは、人間と機械の両方がプログラムをより深く理解し、より効果的に維持するために使用できます。

ここでのコツは、定数を避けることではなく、構文上のプロパティではなく、セマンティックなプロパティで名前を付けることです。使用されている定数は何ですか?プログラムのビジネスドメインがタイポグラフィ、英語の構文解析などである場合を除いて、これを呼び出さないでください。モノのセマンティクスを明確にするために、それまたはそのようなものを呼び出します。CommaListSeparator


42
ここであなたが言っていることの精神には同意しますが、あなたの二番目/三番目の文章は本当に正しくありません。定数は、ファイルのバージョン間で変更できます。実際、私が書いているほとんどのプログラムには、MY_VER「5.03.427.0038」のようなマジックストリングではなく、プログラムの残りの部分で使用できるプログラムの現在のバージョン番号を含むのような名前の定数があります。追加の利点は、セマンティック情報を提供するということです。
モンティハーダー

50
公平を期すために、定数のポイントは、初期化された後実行時に変化しないことであり、コンパイル間で変化しないことではありません。コンパイラの観点から見ると、重要な点は、コンパイラはプログラムが修正できないと仮定できるということです。プログラマが再コンパイル時に修正できるかどうかは、その一定性を変えません。また、ソフトウェアがハードウェアから読み取り専用の値を取得const volatile T*する場合もあります。これは、所定のアドレスへのポインターを逆参照することなどによる場合があります。プログラムは変更できませんが、ハードウェアは変更できます。
ジャスティンタイム

6
@MontyHarder:良い点。私の意見では、私は通常、定数(永遠に変わらないはずです)と、一度割り当てられる変数(バージョンごとに、実行ごとに、など)を区別する言語を使用しているという事実に基づいています。定数と変数は別のものです。1つは同じままで、1つは時間とともに変化します。
エリックリッパー

7
@SteveCox:同意します。C / C ++が「const」を特徴付ける方法は奇妙であり、用途は限られています。定数に必要な特性は、値が変わらないことです。一部の関数では値を変更できますが、他の関数では変更できません。
エリックリッパー

15
「定数は定義によって変わらないため、これは定数を使用する理由ではありません。定数が変更された場合、それは定数ではありませんでしたか?」コンパイル時に定数を変更することは(明らかにランタイムではありません)、まったく正常です。そのため、そもそも明確にラベル付けされた「もの」にしたのです。もちろん、OPの定数はジャンクですが、何かを考えるconst VERSION='3.1.2'か、const KEYSIZE=1024または何でも。
AnoE

61

いいえ、それは愚かです。

必ずしも馬鹿げているわけでないのは、ローカライズのためにそのようなものを名前付きラベルに引き込むことです。たとえば、アメリカで千の区切り記号カンマ(1,000,000)ですが、他のロケールではコンマではありません。それを名前付きラベル(適切な非コンマ名)に入れると、プログラマーはそれらの詳細を無視/抽象化できます。

しかし、「マジックストリングが悪い」という理由で定数を作成することは、単に貨物を栽培することです。


8
通常、ローカライズは単なる文字列定数よりも複雑です。たとえば、すべてのリスト項目の間にリスト区切り文字が必要な言語もあれば、最後の項目の前の区切り文字を除外する言語もあります。そのため、通常はローカライズされた定数ではなく、ローカライズされたルールが必要です。
ヴラド

19
実際、千単位の区切り文字は、他のロケール(中国/日本)では必ずしも千単位の区切り文字ではありません。一定の桁数(インド)の後でも設定されません。ああ、それが1000区切り文字か1000000区切り文字(メキシコ)かによって異なる区切り文字があるかもしれません。ただし、一部のロケール(Farsi)で0〜9のASCII数字を使用しない場合ほど問題はありません。ux.stackexchange.com/questions/23667/...
ピーター

1
@Vladローカリゼーションはそれよりもはるかに複雑ですが、千単位の区切り記号はよく知られている例です。

それはローカライズ戦略に依存します...あなたはそれを翻訳するためにあなたのプログラムのすべての定数を変更しますか?または、ファイル(または他のデータストア)から値を読み取り、効果的にランタイム変数にする必要がありますか?
パエロエベルマン

その場合、定数としてはまったく役に立ちません。プログラムはロケール用に再コンパイルする必要がありますが、これはひどい習慣です。これらは、定義ファイルからロードされ、必要に応じて検索される変数である必要があります。私はその点に反対しているわけではない(私は答えに賛成票を投じた)が、この問題に関してもっと難しい立場を取るだろう。

29

あいまいになるか、いくつかの異なる目的に使用される文字がいくつかあります。たとえば'-'、ハイフン、マイナス記号、またはダッシュとしても使用します。次のように別々の名前を作成できます。

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

後で、コードを次のように再定義することにより、明確にするためにコードを変更することを選択できます。

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

これが、特定の単一文字に定数を定義することを検討する理由かもしれません。 ただし、この方法であいまいな文字の数は少ないです。せいぜい、あなたはそれらのためだけにそれをするだろうと思われます。また、この方法でコードを分解する前に、実際にあいまいな文字を区別する必要があるまで待つことができると主張します。

表記規則は言語や地域によって異なる可能性があるため、翻訳テーブルからこのようなあいまいな句読点をロードする方がよいでしょう。


私にとってこれは、1つの文字定数を作成することができます唯一の正当な理由である
FP

2
-emダッシュとして使用することは非常に誤解を招く可能性があります...ほとんどのフォントではそれを短くするのは非常に重要です。(ダッシュよりもさらに短いです。)
PaŭloEbermann

OK、最良の例ではありません。私はstringsではなくs から始め、ダッシュにwchar_tは標準の原稿規則を使用し"--"ました。しかし、元の例は単一の文字を使用していたため、質問に忠実であるように切り替えました。-特に固定ピッチフォントで作業している場合、ダッシュを打つ人がいます。
エイドリアンマッカーシー

1
@PaŭloEbermannいいえ、伝統的にemダッシュは書体の「m」文字の幅であり、enダッシュは「n」文字の幅です。
ディズリー

@Dizzleyはい、ハイフン幅<n幅<m幅。
パエロエベルマン

22

定数は意味を追加する必要があります。

COMMAをコンマとして定義しても意味はありません。コンマはコンマであることがわかっているからです。代わりに、意味を破棄します。これは、実際にはCOMMAが実際にはコンマではなくなった可能性があるためです。

目的にコンマを使用し、名前付き定数を使用する場合は、目的に応じて名前を付けます。例:

  • city + CharacterClass.COMMA + state =悪い
  • city + CITY_STATE_DELIMITER + state =良い

書式設定に関数を使用する

私は個人的には好んでFormatCityState(city, state)おり、短くてテストケースに合格する限り、その関数の本体がどのように見えるかを気にしません。


1
ああ、しかし、コンマは常に同じコンマとは限りません。COMMA = '\ u0559'または '\ u060C'など(Unicodeを参照)を定義するか、後で変数に変換して構成ファイルから読み取ることもできます。そのように、それはまだ同じ意味を持ちますが、ただ異なる値を持ちます。どのようにそのことについて。
ミスターリスター

2
@MrLister:YAGNI。その必要がある場合:素晴らしい!あなたには素晴らしい解決策があります。ただし、そうしない場合は、コードを乱雑にしないでください。また、私の経験では、コードベースに機能のない抽象化を導入しようとすると、人々は一貫性に優れていません。そのため、選択が重要となる十分なサイズと年齢のプログラムで、他のコードポイントを使用する目的でCOMMAを定義した場合でも、その定数はどこにでも使用されるわけではないことがわかります。 (逆に不適切に使用された可能性もあります)。
イーモンネルボンヌ16

17

定数のCOMMAは、デバンクよりも優れている','","、かなり簡単であるという考え。もちろん、それが理にかなっている場合があります。たとえば、final String QUOTE = "\"";すべてのスラッシュなしで読みやすさを大幅に節約しますが、言語制御文字のようなものを除き、私はそれらが非常に有用である\ 'とは"思いません。

使用するのfinal String COMMA = ","は悪い形だけでなく、危険です!誰かがから、セパレータを変更したいとき","";"、彼らは定数にファイルを変更行くかもしれないCOMMA = ";"、それは彼らがそうするために高速ですので、それだけで動作します。ただし、COMMAを使用していた他のすべてのものは、外部の消費者に送信されるものも含めてセミコロンです。したがって、すべてのテストに合格します(マーシャリングとアンマーシャリングのコードもすべてCOMMAを使用したため)が、外部テストは失敗します。

便利なのは、便利な名前を付けることです。そして、はい、時には複数の定数が同じ内容で異なる名前を持つことがあります。たとえばfinal String LIST_SEPARATOR = ","

したがって、あなたの質問は「リテラルよりも単一の文字定数である」であり、答えは明確にいいえであり、そうではありません。しかし、これらの両方よりも優れているのは、その目的が明示的に示されている狭いスコープの変数名です。確かに、これらの追加の参照にいくつかの余分なバイトを費やします(おそらくそれらはコンパイルされないと仮定します)が、長期的なメンテナンスでは、アプリケーションのコストの大部分があります時間をかける価値があります。


ターゲットプラットフォームに応じて、DISP_APOSTROPHEを条件付きでASCII 0x27またはUnicodeの単一右引用文字(より活字的に適切なアポストロフィの表現)として定義するのはどうですか?
supercat

3
実際QUOTEの例では、一般的に/俗として知られているものに代入されているので、それは同様に悪い考えであることを証明 DOUBLE QUOTEし、QUOTE意味SINGLE_QUOTEがより正確と呼ばれていますAPOSTROPHE

3
@JarrodRoberson引用符は個人的には単一引用符を意味するとは思わない-しかし、それはあなたができる限り曖昧さを取り除くもう一つの正当な理由だ!
corsiKa

2
QUOTE追加の理由でこの例は好きではありません-それで構築された文字列の読み取りがさらに難しくなり"Hello, my name is " + QUOTE + "My Name" + QUOTEますが、これは些細な例ですが、それでも見た目は悪いです。ああ、確かに、連結の代わりにトークンを置き換えることもできます"Hello, my name is %sMy Name%s".format(QUOTE, QUOTE)。しかし、ちょっと、インデックストークンを試してみましょう"Hello, my name is {0}My Name{0}".format(QUOTE)。引用符を使用して生成された重要な文字列はさらに悪化します。
VLAZ

2
@corsiKa-エスケープされた実際の引用とともに生きます。エスケープできない場合、使用するIDEがすぐに文句を言うでしょう。コードもおそらくコンパイルされません。見つけるのはかなり簡単です。"My name is" + QUOTE + "My Name" + QUOTE実際に同じ間違いを3回繰り返して上記のコメントを書いたときに、間違いを犯すのは簡単です。見つけられますか?少し時間がかかる場合は、isの後の不足しているスペースです。文字列をフォーマットしますか?その場合、置換する複数のトークンを含む文字列はさらに悪くなります。読みやすくするためにどのように使用するのですか?
VLAZ

3

字句解析器と構文解析器を作成し、整数定数を使用して端末を表現しました。単純にするために、たまたま単一文字端末はASCIIコードを数値として持っていましたが、コードはまったく別のものであった可能性があります。そのため、定数値として '、'のASCIIコードが割り当てられたT_COMMAがあります。ただし、ASCIIセットを超える整数が割り当てられた非端末の定数もありました。yaccやbisonなどのパーサージェネレーター、またはこれらのツールを使用して作成されたパーサーを見ると、基本的に誰もがそれを行ったという印象を受けました。

したがって、他のすべての人と同様に、コード全体でリテラルの代わりに定数を使用するという明確な目的のために定数を定義することは無意味であると思いますが、あなたが説明するような定数。パーサーの場合、定数は文字リテラルを表すためだけのものではないことに注意してください。それらは、たまたま文字リテラルである可能性があるエンティティを表します。

対応するリテラルの代わりに定数を使用することが理にかなっている、いくつかの孤立したケースを考えることができます。たとえば、UNIXボックスではNEWLINEをリテラル「\ n」に定義しますが、WindowsまたはMacボックスでは「\ r \ n」または「\ n \ r」を定義します。表形式のデータを表すファイルの解析についても同じことが言えます。FIELDSEPARATORおよびRECORDSEPARATOR定数を定義できます。これらの場合、特定の機能を果たす文字を表す定数を実際に定義しています。それでも、あなたが初心者プログラマーである場合、フィールドセパレーター定数をCOMMAと名付け、FIELDSEPARATORと呼ぶべきであることに気付かないかもしれません。そして、気付くまでにコードは生産中であり、次の事業、

最後に、あなたが記述の練習かもしれないあなたは、特定の文字エンコーディングでエンコードされたデータを処理するコードを記述し、いくつかのケースでは意味をなすが、ISO-8859-1を言うが、エンコーディングは後で変更することが予想されます。もちろん、このような場合、ローカライズまたはエンコードおよびデコードライブラリを使用して処理する方がはるかに理にかなっていますが、何らかの理由でそのようなライブラリを使用してエンコードの問題を処理できなかった場合は、定数を使用してソースコード全体に散らばっているハードコーディングされたリテラルの代わりに、単一のファイルで再定義する必要がある場合は、方法があります。

リンク先の記事について:文字リテラルを定数に置き換えることを主張しようとは思わない。インターフェイスを使用して定数をコードベースの他の部分にプルする方法を説明しようとしていると思います。これを説明するために使用される定数の例は、非常にひどく選択されていますが、私はそれらがどんな意味でも重要ではないと思います。


2
インターフェイスを使用して定数をコードベースの他の部分にプルする方法を説明しようとしていると思います。これはさらに悪いアンチパターンであり、密結合と低凝集性でもありますが、それを行う正当な理由もありません。

3

ここでのすべての素晴らしい答えに加えて、良いプログラミングは、同じコードを何度も繰り返すことなく、自分自身や他の人によって構築できる適切な抽象化を提供することだと考えてください。

優れた抽象化により、コードは使いやすく、保守も簡単になります。

DELIMITER=':'は、それ自体が貧弱な抽象概念であり、それよりも優れているだけであることに完全に同意しますCOLON=':'(後者は完全に貧しいため)。

文字列と区切り文字を含む適切な抽象化には、1つ以上の個々のコンテンツアイテムを文字列にパックする方法と、パックされた文字列からもアンパックする方法が含まれます。このような抽象化は、ほとんどの言語ではクラスとして概念としてバンドルされます。たとえば、このクラスが使用されているすべての場所を検索し、いくつかの抽象化が使用される各ケースでパックされた文字列の形式に関するプログラマの意図を確信できるという点で、その使用は実質的に自己文書化されます。

このような抽象化が提供されると、DELIMITERorまたはCOLONisの値を確認することなく簡単に使用でき、実装の詳細の変更は一般に実装に限定されます。つまり、要するに、これらの定数は、適切な抽象化の中に隠された実装の詳細でなければなりません。

定数を使用する主な魅力は、変更が必要なときにメンテナンスを最小限に抑えることです。

通常、いくつかの関連する機能を組み合わせた優れた抽象化は、メンテナンスを最小限に抑えるのに適しています。まず、プロバイダーをコンシューマーから明確に分離します。第二に、実装の詳細を隠し、代わりに直接便利な機能を提供します。第三に、いつどこで使用されているかを高レベルで文書化します。


2

このような定数が効果的に使用されているのを一度目にしたのは、既存のAPIまたはドキュメントを一致させることです。COMMA特定のソフトウェアがCOMMA抽象構文ツリーのタグとして使用されるパーサーに直接接続されていたため、使用されているようなシンボルを見てきました。また、正式な仕様に一致するために使用されることも確認しました。正式な仕様では、可能な限り完全に明確にしたいという理由でCOMMAはなく、シンボルが表示さ','れることがあります。

どちらの場合も、名前の付いたシンボルを使用COMMAすると、別の方法でばらばらになった製品に凝集性を提供できます。その値は、過度に冗長な表記法のコストを上回る場合があります。


2

リストを作成しようとしていることに注意してください。

したがって、次のようにリファクタリングします。 String makeList(String[] items)

つまり、データの代わりにロジックを除外します
言語はリストの表現方法が異なる場合がありますが、コンマは常にコンマです(トートロジーです)。したがって、言語が変更された場合、コンマ文字を変更しても役に立ちませんが、これは役立ちます。


0

これが仲間の開発者によってアプリケーションの一部として記述されたクラスである場合、これはほぼ間違いなく悪い考えです。他の人が既に指摘したようにSEPARATOR = ','、値を変更できる場所などの定数を定義することは理にかなっています。

ただし、名前がその内容を正確に記述する定数を宣言するのが理にかなっている場合と、定数の名前を適切に変更しないと値を変更できない場合が少なくとも2つあります。

  • 数学定数または物理定数PI = 3.14159。ここで、定数の役割は、記号名PIが表す値よりもはるかに短く、読みやすいため、ニーモニックとして機能することです。
  • パーサー内の記号の完全なリストまたはキーボード上のキー。ほとんどまたはすべてのUnicode文字を含む定数のリストを用意するのも理にかなっているかもしれません。などの一部の文字Aは明白であり、はっきりと認識できます。しかし、あなたは簡単に伝えることができますАし、A離れて?最初の文字キリル文字Аで、後者はラテン文字Aです。それらはグラフィカルにほとんど同じですが、異なるUnicodeコードポイントで表される異なる文字です。私はむしろ定数CYRILLIC_CAPITAL_Aを持っていて、LATIN_CAPITAL_A私のコードでは、ほぼ同一に見える2つの文字よりも。もちろん、キリル文字を含まないASCII文字のみで作業することがわかっている場合、これは無意味です。同様に、私は毎日ラテンアルファベットを使用しているため、中国語の文字を必要とするプログラムを作成する場合は、理解できない文字を挿入するよりも定数を使用することをお勧めします。日常的に漢字を使用している人にとっては、漢字は明白かもしれませんが、ラテン文字は名前付き定数として表現する方が簡単かもしれません。したがって、ご覧のとおり、それはコンテキストに依存します。それでも、作成者はライブラリの使用方法や特定のアプリケーションで読みやすさを向上させるために定数が必要な文字を事前に知ることができないため、ライブラリにはすべての文字の記号定数が含まれる場合があります。

ただし、このような場合は通常、システムクラスまたは専用ライブラリによって処理され、アプリケーション開発者によって記述されたコード内で発生することは、非常に特別なプロジェクトに取り組んでいない限り非常にまれです。


-1

多分。

単一文字の定数を区別するのは比較的困難です。したがって、カンマではなくピリオドを追加しているという事実を見逃すのはかなり簡単です

city + '.' + state

一方、それは比較的難しい間違いです

city + Const.PERIOD + state

国際化およびグローバリゼーション環境によっては、ASCIIアポストロフィとWindows-1252のオープンおよびクローズアポストロフィ(またはASCIIの二重引用符とWindows-1252のオープンおよびクローズの二重引用符)の違いが大きく、視覚化が難しいことで有名ですコードで。

おそらく、コンマではなくピリオドを誤って入力することが重要な機能上の問題であった場合、タイプミスを見つける自動テストが行​​われるでしょう。ソフトウェアがCSVファイルを生成している場合、テストスイートが、市と州の間に期間があることを非常に迅速に発見すると期待しています。ソフトウェアがさまざまな国際化構成を持つクライアントで実行されることになっている場合、おそらくテストスイートは各環境で実行され、アポストロフィが必要な場合はMicrosoftのオープンクォートがある場合に取得されます。

特に包括的なテストスイートがない古いコードを使用している場合でも、これらの問題を回避できる詳細なコードを選択する方が理にかなっているプロジェクトを想像できます。グリーンフィールド開発プロジェクト。また、特定のアプリケーションで問題となる可能性がある句読点文字だけでなく、すべての句読点文字に定数を追加することは、おそらく過度の過剰です。


2
いくつかのバカConst.PERIODが等しくなると~どうなりますか?名前の付いたキャラクターのトートロジーを正当化する理由はありません。それは、現代のプログラミング環境では不要なメンテナンスと複雑さを追加するだけです。基本的に言う一連の単体テストを書くつもりassert(Const.PERIOD == '.')ですか?

3
@JarrodRoberson-それはうんざりするでしょう。しかし、実際のコンマではなくコンマのように見えるUnicode定数を誰かが追加した場合、同じくらいの問題が発生します。私が言ったように、これは私がグリーンフィールド開発プロジェクトで行うようなものではありません。ただし、コンマ/ピリオドまたはアポストロフィ/マイクロソフトのアボミネーションアポストロフィの発行を数回トリップしたむらのあるテストスイートを備えたレガシーコードベースがある場合は、いくつかの定数を作成し、それらを使用するように人々に伝えるのが合理的な方法かもしれませんテストの作成に1年を費やすことなく、コードを改善します。
ジャスティン洞窟

3
あなたのレガシーの例は貧弱なものです。18歳の1,000,000+ LOCコードベースのリファクタリングを終えました。このように、印刷可能なすべての文字が複数回定義されており、異なる名前の競合もあります。そして、何度も名前COMMAが付けられたものが実際に設定されました= SPACE + "," + SPACE。はい、いくつかの馬鹿はSPACE定数を持っていました。私はそれらをすべてリファクタリングし、コードは非常に読みやすく、大学の雇用者は何かを実際に設定するために6レベルの間接性なしで物事を追跡し修正することができました。

-1

単一文字の定数はリテラルよりも優れていますか?

この辺りには多くの混乱が浮かんでいます。それらをバラバラにいじめることができるかどうか見てみましょう。

定数は以下を提供します:

  • 意味論
  • 変更、開発中
  • 間接

単一の文字名に移動しても、セマンティクスにのみ影響します。名前はコメントとして有用で、文脈が明確でなければなりません。値ではなく意味を表現する必要があります。それがすべて単一の文字でうまくできるなら。できない場合は、しないでください。

リテラルと定数はどちらも開発中に変更できます。これがマジックナンバーの問題を引き起こします。文字列もマジックナンバーにすることができます。

セマンティックな意味が存在し、両方が定数である場合、定数がリテラルよりも大きな値を持っているかどうかは間接になります。

インダイレクションは、多くのインダイレクション以外の問題を解決できます。

インダイレクションは、1つの場所でアイデアの値を決定できるため、マジックナンバーの問題を解決できます。意味的には、それが価値があるためには、その名前がそのアイデアが明確であるようにしなければなりません。名前は価値ではなく、アイデアに関するものでなければなりません。

インダイレクションはやり直すことができます。リテラルを検索および置換して変更を加えることを好む人もいます。42が明らかに生命の意味であり、42のモリブデン原子番号と混同されない限り、それは問題ありません。

単一の文字でそのような有用な区別を行うことができる場所は、コンテキストに大きく依存します。しかし、私はそれを習慣にするつもりはありません。


1
セマンティックが鍵です。「A」が単に「A」であるという意味よりもセマンティックがある場合、同じセマンティックを同じ「参照」にバインドする価値があります。定数であるかどうかは関係ありません。全くもって同じ意見です。
oopexpert

-1

大多数の意見に対する哲学的な矛盾として、私は、洗練されていない19世紀のフランスの農民プログラマーと

単調で永遠に続く明快さ、すべてに対する驚くほど賢明な見方、真実であるという理由だけでの自閉症との膨大な満足を思い出しました。「それをすべて混乱させます!」「彼が亡命中であれば、外に誰もいられない」とターンブルを叫んだ。

GKチェスタトン、ボールと十字架

真実を正しく評価することには何の問題もありません。特にコンピューターと話すときは、真実を述べることに何の問題もありません。

コンピューターに嘘をつくと、

ペリー・ファラー-メリーランド州ジャーマンタウン(More Programming Pearlsより)


しかし、ほとんどの場合、私はそれが馬鹿だと言う人々に同意します。FORTRANのプログラミングを学ぶには若すぎますが'A' = 'Q'、あらゆる種類のすばらしい暗号を再定義して思い付くことができると聞いたことがあります。あなたはこれをしていません。

以前に提起されたi18nの問題を超えて(これはグリフ "COMMA"を再定義するのではなく、DECIMAL_POINTのグリフを本当に再定義する)。人間に意味を伝えるためにフランスのニンジン引用符または英国の単一引用符を作成することは重要であり、それらは実際には定数ではなく変数であるべきです。定数は次のようになりますAMERICAN_COMMA := ','し、comma := AMERICAN_COMMA

また、ビルダーパターンを使用してSQLクエリを構築している場合は、

sb.append("insert into ")
 .append(table_name)
 .append(" values ")
 .append(" ( ")
 .append(val_1)
 .append(",")
 .append(val_2)
 .append(" ); ")

他の何よりも、しかしあなたが定数を追加しようとするなら、それは

INSERT_VALUES_START = " ( "
INSERT_VALUES_END = " ) "
INSERT_VALUES_SEPARATOR = " , "
QUERY_TERMINATOR = ";"

sb.append("insert into ")
 .append(table_name)
 .append(" values ")
 .append(INSERT_VALUES_START)
 .append(val_1)
 .append(INSERT_VALUES_SEPARATOR)
 .append(val_2)
 .append(INSERT_VALUES_END)
 .append(QUERY_TERMINATOR)

ただし、他の誰かがプログラム(またはタイプ)を視聴したことがある場合は、いくつかの興味深い癖に気付くかもしれません。私たち全員が恒星タイピストではありません。私たちの多くは遅くプログラミングに参加したか、ソビエトのキーボード(キーが入力される場所)で育ちました。キーボードで文字を見つけたりオートコンプリートに頼ったりする代わりに、個々の文字カットアンドペーストしたいのです。

文字列を自動補完するものは何もないので、「con」、alt-space、down、down、down、Enterを押してコンマを取得し、「con」、alt-space、down、ダウン、入力します。私はそれをするかもしれません。


文字列リテラルについて覚えておくべきもう1つのことは、それらのコンパイル方法です。少なくともDelphiでは(これが私がスタックに取りつかれている唯一の言語です)、各関数のスタックにポップされたリテラルを作成します。したがって、多くのリテラル=多くの関数オーバーヘッド; function_Aの「、」は、function_Bの「、」と同じメモリビットではありません。これに対処するために、横に構築およびリンクできる「リソース文字列」があります。 Pythonでは、すべての文字列リテラルはオブジェクトであり、実際に使用するのutils.constants.COMMA.join(["some","happy","array","strings"])が良いように思えるかもしれませんが、このページで何度も繰り返される点については素晴らしい考えではありません。


-4

しかし、いつコンマを表すために「、」とは異なるシンボルを使用し始めますか?

ローカリゼーション用。

英語圏の国では、小数部の整数部と小数部を分ける記号は「。」であり、これを「小数点」と呼びます。他の多くの国では、記号は「、」であり、通常は現地語で「コンマ」と同等と呼ばれます。同様に、英語圏の国が「、」を使用して3桁のグループを大きな数字で区切る場合(100万分の1,000,000など)、カンマを小数点として使用する国ではドット(1.000.000)を使用します。

したがって、グローバリゼーションを行っている場合は、DECIMAL_POINTおよびCOMMA定数を作成する場合があります。


2
しかし、その場合、COMMAとDECIMAL_POINTはエンティティの正しい名前ではありません(おそらく、あなたが投票された理由です)。
カイルストランド

特定のローカライズバージョンをコンパイルする必要があります。リテラル定数はそれに適していません。そのユースケースでは、定義ファイルを呼び出し、それらを検索します(定数を含む場合がありますが、定数文字ではなく、定数を検索します)。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.