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
grepmencari 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 MyClassdalam "keadaan default" atau tidak. Selain menempatkan bool nonemptybidang atau serupa ke permukaan default-saat di runtime, yang terbaik yang dapat Anda lakukan adalah menghasilkan contoh baru MyClassdengan 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::pairdan pastikan untuk mendokumentasikan bahwa fungsi Anda melakukan ini.
Jika fungsi pabrik memiliki nama yang unik, mudah grepuntuk namanya dan mencari kecerobohan. Namun, sulit grepuntuk kasus-kasus di mana programmer seharusnya menggunakan fungsi pabrik tetapi tidak .
OCaml
Jika Anda menggunakan bahasa seperti OCaml, maka Anda bisa menggunakan optiontipe (di pustaka standar OCaml) atau eithertipe (tidak di pustaka standar, tetapi mudah untuk menggulir sendiri). Atau defaultabletipe (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 defaultableseperti yang ditunjukkan di atas lebih baik daripada pasangan karena pengguna harus mencocokkan pola untuk mengekstrak 'adan tidak bisa begitu saja mengabaikan elemen pertama dari pasangan.
Setara dengan defaultablejenis seperti yang ditunjukkan di atas dapat digunakan dalam C ++ menggunakan std::variantdengan dua contoh dari jenis yang sama, tetapi bagian dari std::variantAPI tidak dapat digunakan jika kedua jenisnya sama. Juga penggunaan aneh std::variantkarena 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 DefaultedMyClassyang mewarisi MyClassdan mengembalikannya dari fungsi pabrik Anda. Itu memberi Anda fleksibilitas dalam hal "mematikan" fungsionalitas dalam kasus default jika Anda perlu.