私はJavaのDate-Time APIを設計または作成しなかったので、「なぜこのようにしたのか」と断言することはできません。しかし、私は彼らがこのようにそれをするべきである2つの主要な理由を提案することができます:
- 表現力
- 平行形
まず、コンテキストを検討してください。Javaの日付と時刻のコードは、非常にトリッキーな主題を扱う大きくて複雑なパッケージです。「時間」と同様に、この概念の実装には、地理的な場所(タイムゾーン)、言語、カレンダーシステム、時計の解像度、時間スケール、数値表現、データソース、および間隔に応じたさまざまな解釈と形式が含まれます。修正デルタ(うるう年/日など)は一般的で、いつでも不規則に挿入されることがあります(うるう秒)。しかし、パッケージはコア機能であり、広く使用される可能性が高いため、これらすべてのバリエーションを正確かつ正確に処理することが期待されています。それは難しい注文です。その結果、当然のことながら、それぞれに多くのメソッドを持つ多くのクラスを含む複雑なAPIができます。
では、なぜof
「通常の」クラスコンストラクタではなくメソッドを使用するのでしょうか。以下のためにたとえば、なぜLocalDate.of(...)
、LocalDate.ofEpochDay(...)
と、LocalDate.ofYearDay(...)
というだけの一握りよりもnew LocalDate(...)
呼び出し?
まず、表現力:個々の名前付きメソッドは、構築の意図と消費されるデータの形式を表現します。
とりあえず、Javaのメソッドのオーバーロードが、必要なさまざまなコンストラクタを許可するのに十分であると仮定します。(ダックタイピング、単一vs動的vs複数ディスパッチについての言語機能の議論に入らないで、私はただ言います:時々これは真であり、時々そうではありません。今のところ、技術的な制限はないと仮定してください。)
コンストラクターのドキュメントに「単一のlong
値のみが渡された場合、その値は年ではなくエポック日数として解釈される」と記載される可能性があります。他のコンストラクターに渡される低レベルのデータ型が異なる場合(たとえば、エポックの場合のみが使用されlong
、他のすべてのコンストラクターがを使用する場合int
)、これで問題が解決する可能性があります。
LocalDate
単一long
のでコンストラクタを呼び出すコードを見ると、特に年が渡されることは間違いなく最も一般的なケースであり、年が渡されるコードに非常に似ています。その共通のコンストラクタを持つことは可能かもしれませんが、それは必ずしも大きな明快さをもたらすとは限りません。
ofEpochDay
ただし、APIを明示的に呼び出すと、ユニットと意図の明確な違いがわかります。同様にLocalDate.ofYearDay
、共通month
パラメーターがスキップされていること、および日パラメーターはまだであるがint
、ではdayOfYear
ないことを示しdayOfMonth
ます。明示的なコンストラクターメソッドは、何が起こっているかをより明確に表現することを目的としています。
PythonやJavaScriptなどの動的およびダック型の言語には、代替解釈を通知する他の手段(オプションのパラメーターや帯域外センチネル値など)がありますが、PythonおよびJS開発者でさえ、異なる解釈を示すために区別されたメソッド名を使用することがよくあります。技術的な制約(静的に型付けされた単一ディスパッチ言語)とその文化的慣習/イディオムの両方を考えると、Javaではさらに一般的です。
第二に、並列形式。LocalDate
2つのof
メソッドに加えて、またはその代わりに、標準のJavaコンストラクターを提供できます。しかし、何のために?それはまだ必要ofEpochDay
とofDayYear
それらのユースケースのために。一部のクラスは、コンストラクターと同等のofXYZ
メソッドの両方を提供します-たとえば、両方Float('3.14')
とFloat.parseFloat('3.14')
存在します。しかしofXYZ
、何かにコンストラクタが必要な場合は、常にそれらを使用しないのはなぜですか?それはより単純で、より規則的で、より並列です。不変タイプとして、大部分のLocalDate
方法は、コンストラクタです。ある方法の七大グループコンストラクトは新しいインスタンス(つまりは、それぞれat
、from
、minus
、of
、 parse
、plus
、およびwith
プレフィックス)。LocalDate
の60以上のメソッドのうち、35以上がデファクトコンストラクタです。これらのうち2つだけを簡単に標準のクラスベースのコンストラクタに変換できます。他のすべてと平行ではない方法でこれらの2を特殊ケース化することは本当に意味がありますか?これら2つの特殊なケースのコンストラクターを使用するクライアントコードは、特に明確または単純になりますか?おそらく違います。それは、クライアントコードをより多様にし、簡単ではなくなるかもしれません。