Mengapa java.time memiliki metode untuk membuat objek, bukan hanya konstruktor?

8

Dalam paket java.time baru kelas inti menggunakan metode pabrik ofbukan konstruktor publik. Meskipun saya suka kosmetik ofmetode ini, saya tidak bisa melihat alasan yang bagus untuk tidak menggunakan konstruktor. Dokumentasi yang saya temukan hanya menjelaskan bahwa ini adalah masalahnya dan tidak benar-benar menjelaskan mengapa itu terjadi.

Kutipan dari tutorial :

Sebagian besar kelas di Date-Time API membuat objek yang tidak dapat diubah, yang berarti bahwa, setelah objek dibuat, itu tidak dapat dimodifikasi. Untuk mengubah nilai objek yang tidak dapat diubah, objek baru harus dikonstruksi sebagai salinan asli dari yang asli. Ini juga berarti bahwa Date-Time API, menurut definisi, aman-utas. Ini memengaruhi API karena sebagian besar metode yang digunakan untuk membuat objek tanggal atau waktu diawali dengan, dari, atau dengan, bukan konstruktor, dan tidak ada metode yang ditetapkan.

softarn
sumber

Jawaban:

9

Metode pabrik memungkinkan penyederhanaan konstruktor - perbedaan yang instance dalam waktu diwakili oleh Object dapat dipisahkan dari perhitungan instan.

Ada banyak metode pabrik, beberapa melakukan penguraian String, beberapa mengkonversi dari beberapa representasi tanggal atau waktu lainnya, tetapi semua itu dapat terjadi sebelum Obyek harus dibuat (jika membuat Obyek baru bahkan diperlukan sama sekali - juga bisa menjadi cache satu).

Keuntungan besar lainnya adalah bahwa metode pabrik dapat memiliki nama deskriptif : metode untuk parsing representasi String diberi nama misalnya LocalTime.parse- yang tidak mungkin dengan konstruktor.

Hulk
sumber
Untuk meningkatkan jawaban ini, Anda bisa menambahkan contoh dari misalnya objek Bulan yang memilih instance mana untuk kembali dalam metode pabrik.
softarn
8

Tidak selalu diperlukan untuk membuat objek baru saat mendapatkan nilai dari tipe yang tidak dapat diubah. Metode pabrik dapat mengembalikan objek yang telah dibuat sementara panggilan konstruktor selalu membuat objek baru.

Ada beberapa keuntungan lain untuk metode pabrik, tetapi mereka tidak terkait erat dengan keabadian dan API Tanggal-Waktu. Misalnya, metode pabrik memiliki nama dan mereka dapat mengembalikan objek dari beberapa subtipe.

BERASAL DARI
sumber
5

Saya tidak mendesain atau menulis API Tanggal-Waktu Java, jadi saya tidak dapat secara definitif mengatakan "mengapa mereka melakukannya dengan cara ini." Namun saya dapat menyarankan dua alasan utama mereka harus melakukannya dengan cara ini:

  1. Kekuatan ekspresif
  2. Bentuk paralel

Pertama, pertimbangkan konteksnya: Tanggal dan kode waktu Java adalah paket besar dan rumit yang berurusan dengan masalah yang sangat rumit. Seperti halnya "waktu", penerapan konsep melibatkan lusinan interpretasi dan format, dengan variasi di seluruh lokasi geografis (zona waktu), bahasa, sistem kalender, resolusi jam, skala waktu, representasi numerik, sumber data, dan interval. Delta korektif (misalnya tahun kabisat / hari) adalah umum, dan dapat dimasukkan secara tidak teratur kapan saja (detik kabisat). Namun paket tersebut adalah fitur inti, kemungkinan akan digunakan secara luas, dan diharapkan dapat menangani semua variasi tersebut dengan benar dan tepat. Ini tugas berat. Hasilnya, tidak mengherankan, adalah API yang kompleks termasuk banyak kelas, masing-masing dengan banyak metode.

Sekarang, mengapa menggunakan ofmetode daripada konstruktor kelas "biasa"? Untuk contoh , mengapa LocalDate.of(...), LocalDate.ofEpochDay(...)dan LocalDate.ofYearDay(...)bukan hanya segelintir new LocalDate(...)panggilan?

Pertama, kekuatan ekspresif : Metode individu bernama menyatakan maksud konstruksi dan bentuk data yang dikonsumsi.

Asumsikan sejenak bahwa kelebihan metode Java cukup untuk memungkinkan berbagai konstruktor yang Anda inginkan. (Tanpa membahas fitur bahasa di sekitar mengetik bebek dan pengiriman tunggal vs dinamis vs beberapa saya hanya akan mengatakan: kadang-kadang ini benar, kadang tidak. Untuk saat ini, anggap saja tidak ada batasan teknis.)

Mungkin saja dokumentasi konstruktor menyatakan "ketika hanya melewati satu longnilai tunggal , nilai itu ditafsirkan sebagai hitungan hari, bukan satu tahun." Jika tipe data tingkat rendah yang diteruskan ke konstruktor lain berbeda (mis. Hanya kasus zaman yang digunakan long, dan semua konstruktor lainnya digunakan int), Anda mungkin lolos dengan ini.

Jika Anda melihat kode memanggil LocalDatekonstruktor dengan satu long, itu akan terlihat sangat mirip dengan kode di mana satu tahun dilewatkan, terutama dengan melewati satu tahun bisa dibilang kasus yang paling umum. Memiliki konstruktor yang sama itu mungkin, tetapi itu tidak selalu mengarah pada kejelasan yang besar.

Namun API yang secara eksplisit menyatakan ofEpochDay, menandakan perbedaan yang jelas dalam unit dan niat. Demikian pula LocalDate.ofYearDaymenandakan bahwa monthparameter umum sedang dilewati, dan bahwa parameter hari, sementara masih merupakan int, dayOfYearbukan a dayOfMonth. Metode konstruktor eksplisit dimaksudkan untuk mengungkapkan apa yang terjadi dengan kejelasan yang lebih besar.

Bahasa yang diketik secara dinamis dan bebek seperti Python dan JavaScript memiliki cara lain untuk menandai interpretasi alternatif (misalnya parameter opsional dan nilai sentinel out-of-band ), tetapi bahkan pengembang Python dan JS sering menggunakan nama metode yang dibedakan untuk menandai interpretasi yang berbeda. Ini bahkan lebih umum di Jawa, mengingat kedua kendala teknisnya (itu adalah bahasa yang diketik secara statis, pengiriman tunggal) dan konvensi / idiom budaya.

Kedua, bentuk paralel . LocalDatedapat memberikan konstruktor Java standar sebagai tambahan, atau sebagai pengganti, dua ofmetodenya. Tetapi untuk tujuan apa? Masih perlu ofEpochDaydan ofDayYearuntuk kasus penggunaan tersebut. Beberapa kelas memang menyediakan konstruktor dan metode yang setara ofXYZ- misalnya, keduanya Float('3.14')dan Float.parseFloat('3.14')ada. Tetapi jika Anda membutuhkan ofXYZkonstruktor untuk beberapa hal, mengapa tidak menggunakannya setiap saat? Itu lebih sederhana, lebih teratur, dan lebih paralel. Sebagai jenis berubah, yang mayoritas dari LocalDatemetode yang konstruktor. Ada kelompok utama tujuh metode yang membangun kasus baru (masing-masing, at, from, minus, of, parse,plus, dan withawalan). Dari LocalDate60+ metode, 35+ adalah konstruktor de facto . Hanya 2 yang dapat dengan mudah dikonversi menjadi konstruktor berbasis kelas standar. Apakah benar-benar masuk akal untuk memberi case khusus pada keduanya dengan cara yang tidak paralel dengan yang lainnya? Apakah kode klien menggunakan dua konstruktor kasus khusus menjadi lebih jelas atau lebih sederhana? Mungkin tidak. Bahkan mungkin membuat kode klien lebih bervariasi dan kurang mudah.

Jonathan Eunice
sumber