Jangan gunakan jika Anda bisa menghindarinya. Gunakan fungsi pabrik untuk mengembalikan jenis opsi, tupel, atau jenis jumlah khusus. Dengan kata lain, mewakili nilai yang berpotensi gagal standar dengan tipe yang berbeda dari nilai yang dijamin tidak akan gagal bayar.
Pertama, mari kita daftar desiderata lalu pikirkan tentang bagaimana kita dapat mengekspresikan ini dalam beberapa bahasa (C ++, OCaml, Python)
- menangkap penggunaan objek default yang tidak diinginkan pada waktu kompilasi.
- memperjelas apakah nilai yang diberikan berpotensi gagal atau tidak saat membaca kode.
- pilih nilai default kami yang masuk akal, jika berlaku, satu kali per jenis . Tentu saja jangan memilih default yang berpotensi berbeda di setiap situs panggilan .
- membuatnya mudah untuk alat analisis statis atau manusia dengan
grep
mencari kesalahan potensial.
- Untuk beberapa aplikasi , program harus dilanjutkan secara normal jika secara tak terduga diberi nilai default. Untuk aplikasi lain , program harus dihentikan segera jika diberi nilai default, idealnya dengan cara yang informatif.
Saya pikir ketegangan antara Pola Obyek Null dan pointer nol berasal dari (5). Jika kita dapat mendeteksi kesalahan cukup awal, (5) menjadi moot.
Mari pertimbangkan bahasa ini dengan bahasa:
C ++
Menurut pendapat saya, kelas C ++ umumnya harus dibangun-standar karena memudahkan interaksi dengan perpustakaan dan membuatnya lebih mudah untuk menggunakan kelas dalam wadah. Ini juga menyederhanakan pewarisan karena Anda tidak perlu memikirkan tentang konstruktor superclass mana yang harus dihubungi.
Namun, ini berarti bahwa Anda tidak dapat mengetahui dengan pasti apakah nilai tipe MyClass
dalam "keadaan default" atau tidak. Selain menempatkan bool nonempty
bidang atau serupa ke permukaan default-saat di runtime, yang terbaik yang dapat Anda lakukan adalah menghasilkan contoh baru MyClass
dengan cara yang memaksa pengguna untuk memeriksanya .
Saya akan merekomendasikan menggunakan fungsi pabrik yang mengembalikan std::optional<MyClass>
, std::pair<bool, MyClass>
atau referensi nilai-r ke std::unique_ptr<MyClass>
jika mungkin.
Jika Anda ingin fungsi pabrik Anda mengembalikan semacam "tempat penampung" yang berbeda dari yang dibangun secara default MyClass
, gunakan a std::pair
dan pastikan untuk mendokumentasikan bahwa fungsi Anda melakukan ini.
Jika fungsi pabrik memiliki nama yang unik, mudah grep
untuk namanya dan mencari kecerobohan. Namun, sulit grep
untuk kasus-kasus di mana programmer seharusnya menggunakan fungsi pabrik tetapi tidak .
OCaml
Jika Anda menggunakan bahasa seperti OCaml, maka Anda bisa menggunakan option
tipe (di pustaka standar OCaml) atau either
tipe (tidak di pustaka standar, tetapi mudah untuk menggulir sendiri). Atau defaultable
tipe (saya mengarang istilah defaultable
).
type 'a option =
| None
| Some of 'a
type ('a, 'b) either =
| Left of 'a
| Right of 'b
type 'a defaultable =
| Default of 'a
| Real of 'a
A defaultable
seperti yang ditunjukkan di atas lebih baik daripada pasangan karena pengguna harus mencocokkan pola untuk mengekstrak 'a
dan tidak bisa begitu saja mengabaikan elemen pertama dari pasangan.
Setara dengan defaultable
jenis seperti yang ditunjukkan di atas dapat digunakan dalam C ++ menggunakan std::variant
dengan dua contoh dari jenis yang sama, tetapi bagian dari std::variant
API tidak dapat digunakan jika kedua jenisnya sama. Juga penggunaan aneh std::variant
karena konstruktor jenisnya tidak disebutkan namanya.
Python
Lagi pula, Anda tidak mendapatkan waktu kompilasi untuk memeriksa Python. Tapi, karena diketik secara dinamis, biasanya tidak ada keadaan di mana Anda memerlukan instance placeholder dari beberapa jenis untuk menenangkan kompiler.
Saya akan merekomendasikan hanya melempar pengecualian ketika Anda akan dipaksa untuk membuat contoh default.
Jika itu tidak dapat diterima, saya akan merekomendasikan membuat DefaultedMyClass
yang mewarisi MyClass
dan mengembalikannya dari fungsi pabrik Anda. Itu memberi Anda fleksibilitas dalam hal "mematikan" fungsionalitas dalam kasus default jika Anda perlu.