Seperti dicatat dalam komentar oleh @ benjamin-gruenbaum ini disebut perangkap Boolean:
Katakanlah saya memiliki fungsi seperti ini
UpdateRow(var item, bool externalCall);
dan di controller saya, nilai itu externalCall
akan selalu BENAR. Apa cara terbaik untuk memanggil fungsi ini? Saya biasanya menulis
UpdateRow(item, true);
Tetapi saya bertanya pada diri saya sendiri, haruskah saya menyatakan boolean, hanya untuk menunjukkan apa arti nilai 'sejati' itu? Anda bisa tahu itu dengan melihat deklarasi fungsi, tetapi jelas lebih cepat dan lebih jelas jika Anda hanya melihat sesuatu seperti
bool externalCall = true;
UpdateRow(item, externalCall);
PD: Tidak yakin apakah pertanyaan ini benar-benar cocok di sini, jika tidak, di mana saya bisa mendapatkan lebih banyak info tentang ini?
PD2: Saya tidak memberi tag bahasa apa pun karena saya pikir itu masalah yang sangat umum. Lagi pula, saya bekerja dengan c # dan jawaban yang diterima berfungsi untuk c #
data CallType = ExternalCall | InternalCall
di haskell misalnya.Jawaban:
Tidak selalu ada solusi yang sempurna, tetapi Anda memiliki banyak alternatif untuk dipilih:
Gunakan argumen bernama , jika tersedia dalam bahasa Anda. Ini bekerja dengan sangat baik dan tidak memiliki kekurangan tertentu. Dalam beberapa bahasa, argumen apa pun dapat diajukan sebagai argumen bernama, misalnya
updateRow(item, externalCall: true)
( C # ) atauupdate_row(item, external_call=True)
(Python).Saran Anda untuk menggunakan variabel terpisah adalah salah satu cara untuk mensimulasikan argumen bernama, tetapi tidak memiliki manfaat keamanan yang terkait (tidak ada jaminan bahwa Anda menggunakan nama variabel yang benar untuk argumen itu).
Gunakan fungsi berbeda untuk antarmuka publik Anda, dengan nama yang lebih baik. Ini adalah cara lain untuk mensimulasikan parameter bernama, dengan meletakkan nilai paremeter dalam nama.
Ini sangat mudah dibaca, tetapi mengarah ke banyak boilerplate untuk Anda, yang menulis fungsi-fungsi ini. Itu juga tidak bisa menghadapi ledakan kombinatorial ketika ada beberapa argumen boolean. Kelemahan signifikan adalah bahwa klien tidak dapat menetapkan nilai ini secara dinamis, tetapi harus menggunakan jika / yang lain untuk memanggil fungsi yang benar.
Gunakan enum . Masalah dengan boolean adalah bahwa mereka disebut "benar" dan "salah". Jadi, alih-alih perkenalkan jenis dengan nama yang lebih baik (misalnya
enum CallType { INTERNAL, EXTERNAL }
). Sebagai manfaat tambahan, ini meningkatkan keamanan jenis program Anda (jika bahasa Anda mengimplementasikan enum sebagai jenis yang berbeda). Kelemahan dari enum adalah mereka menambahkan jenis ke API Anda yang dapat dilihat secara publik. Untuk fungsi internal murni, ini tidak masalah dan enum tidak memiliki kelemahan yang signifikan.Dalam bahasa tanpa enum, string pendek terkadang digunakan sebagai gantinya. Ini berfungsi, dan bahkan mungkin lebih baik daripada boolean mentah, tetapi sangat rentan terhadap kesalahan ketik. Fungsi kemudian harus segera menyatakan bahwa argumen cocok dengan satu set nilai yang mungkin.
Tidak satu pun dari solusi ini yang memiliki dampak kinerja yang terlarang. Parameter yang dinamai dan enum dapat diselesaikan sepenuhnya pada waktu kompilasi (untuk bahasa yang dikompilasi). Menggunakan string mungkin melibatkan perbandingan string, tetapi biaya yang dapat diabaikan untuk literal string kecil dan sebagian besar jenis aplikasi.
sumber
Solusi yang tepat adalah melakukan apa yang Anda sarankan, tetapi kemas dalam fasad mini:
Keterbacaan mengalahkan pengoptimalan mikro. Anda dapat membeli panggilan fungsi ekstra, tentu saja lebih baik daripada Anda mampu membayar upaya pengembang karena harus melihat semantik bendera Boolean bahkan sekali.
sumber
true
dilakukannya.) Akan bermanfaat bahkan jika itu biaya banyak waktu CPU karena menghemat waktu pengembang, karena waktu CPU jauh lebih murah.UpdateRow(item, true /*external call*/);
akan lebih bersih, dalam bahasa yang memungkinkan sintaks komentar itu. Kembung kode Anda dengan fungsi tambahan hanya untuk menghindari menulis komentar sepertinya tidak layak untuk kasus sederhana. Mungkin jika ada banyak argumen lain untuk fungsi ini, dan / atau beberapa kode rumit sekitar berantakan, itu akan mulai menarik lebih banyak. Tapi saya pikir jika Anda men-debug Anda akan berakhir memeriksa fungsi wrapper untuk melihat fungsinya, dan harus mengingat fungsi mana yang merupakan pembungkus tipis di sekitar API perpustakaan, dan yang sebenarnya memiliki beberapa logika.Mengapa Anda memiliki fungsi seperti ini?
Dalam keadaan apa Anda menyebutnya dengan argumen Panggilan eksternal diatur ke nilai yang berbeda?
Jika salah satu dari, katakanlah, aplikasi klien eksternal dan yang lain berada dalam program yang sama (yaitu modul kode yang berbeda), maka saya berpendapat bahwa Anda harus memiliki dua metode yang berbeda , satu untuk setiap kasus, bahkan mungkin ditentukan pada Antarmuka.
Namun, jika Anda membuat panggilan berdasarkan pada beberapa datum yang diambil dari sumber non-program (misalnya, file konfigurasi atau basis data dibaca), maka metode passing Boolean akan lebih masuk akal.
sumber
Walaupun saya setuju bahwa ideal untuk menggunakan fitur bahasa untuk menegakkan keterbacaan dan keamanan nilai, Anda juga dapat memilih pendekatan praktis : komentar waktu panggilan. Suka:
atau:
atau (benar, seperti yang disarankan oleh Frax):
sumber
UpdateRow(item, /* externalCall */ true )
. Komentar kalimat lengkap jauh lebih sulit diurai, sebenarnya sebagian besar kebisingan (terutama varian kedua, yang juga sangat longgar ditambah dengan argumen).Anda bisa 'memberi nama' bools Anda. Di bawah ini adalah contoh untuk bahasa OO (di mana ia dapat diekspresikan dalam penyediaan kelas
UpdateRow()
), namun konsep itu sendiri dapat diterapkan dalam bahasa apa pun:dan di situs panggilan:
Saya percaya Item # 1 lebih baik tetapi tidak memaksa pengguna menggunakan variabel baru saat menggunakan fungsi. Jika keamanan jenis penting bagi Anda, Anda bisa membuat
enum
tipe danUpdateRow()
menerima ini alih-alihbool
:UpdateRow(var item, ExternalCallAvailability ec);
Anda dapat memodifikasi nama fungsi dengan cara yang mencerminkan makna
bool
parameter dengan lebih baik. Tidak terlalu yakin tapi mungkin:UpdateRowWithExternalCall(var item, bool externalCall)
sumber
externalCall=false
, namanya sama sekali tidak masuk akal. Jawaban Anda yang lain baik.UpdateRowWithUsuallyExternalButPossiblyInternalCall
.Pilihan lain yang belum saya baca di sini adalah: Gunakan IDE modern.
Misalnya IntelliJ IDEA mencetak nama variabel dari variabel-variabel dalam metode yang Anda panggil jika Anda menggunakan literal seperti
true
ataunull
atauusername + “@company.com
. Ini dilakukan dalam font kecil sehingga tidak memakan terlalu banyak ruang pada layar Anda dan terlihat sangat berbeda dari kode yang sebenarnya.Saya masih tidak mengatakan itu ide bagus untuk melempar boolean ke mana-mana. Argumen yang mengatakan bahwa Anda membaca kode jauh lebih sering daripada yang Anda tulis seringkali sangat kuat, tetapi untuk kasus khusus ini sangat tergantung pada teknologi yang Anda (dan kolega Anda!) Gunakan untuk mendukung pekerjaan Anda. Dengan IDE itu jauh lebih sedikit masalah dibandingkan dengan misalnya vim.
Contoh modifikasi dari bagian pengaturan pengujian saya:
sumber
2 hari dan tidak ada yang menyebutkan polimorfisme?
Ketika saya seorang klien yang ingin memperbarui baris dengan item saya tidak ingin memikirkan nama database, URL layanan mikro, protokol yang digunakan untuk berkomunikasi, atau apakah panggilan eksternal atau tidak akan perlu digunakan untuk mewujudkannya. Berhentilah mendorong detail ini pada saya. Ambil saja barang saya dan perbarui baris di suatu tempat.
Lakukan itu dan itu menjadi bagian dari masalah konstruksi. Itu bisa dipecahkan dengan banyak cara. Ini dia:
Jika Anda melihat itu dan berpikir "Tapi bahasa saya telah menamai argumen, saya tidak membutuhkan ini". Baik, bagus, gunakan saja. Jauhkan omong kosong ini dari klien panggilan yang seharusnya tidak tahu apa yang ia bicarakan.
Perlu dicatat bahwa ini lebih dari masalah semantik. Ini juga masalah desain. Lewati boolean dan Anda terpaksa menggunakan percabangan untuk menghadapinya. Tidak terlalu berorientasi objek. Ada dua atau lebih boolean yang bisa lewat? Ingin bahasa Anda memiliki beberapa pengiriman? Lihatlah koleksi apa yang bisa dilakukan ketika Anda menyimpannya. Struktur data yang tepat dapat membuat hidup Anda jauh lebih mudah.
sumber
Jika Anda dapat memodifikasi
updateRow
fungsinya, mungkin Anda dapat mengubahnya menjadi dua fungsi. Mengingat bahwa fungsi tersebut mengambil parameter boolean, saya menduga tampilannya seperti ini:Itu bisa menjadi sedikit bau kode. Fungsi tersebut mungkin memiliki perilaku yang sangat berbeda tergantung pada
externalCall
variabel yang ditetapkan, dalam hal ini ia memiliki dua tanggung jawab yang berbeda. Refactoring menjadi dua fungsi yang hanya memiliki satu tanggung jawab dapat meningkatkan keterbacaan:Sekarang, di mana saja Anda memanggil fungsi-fungsi ini, Anda dapat mengetahui apakah layanan eksternal sedang dipanggil.
Tentu saja tidak selalu demikian. Itu situasional dan masalah selera. Refactoring suatu fungsi yang mengambil parameter boolean menjadi dua fungsi biasanya layak dipertimbangkan, tetapi tidak selalu merupakan pilihan terbaik.
sumber
Jika UpdateRow berada dalam basis kode yang dikontrol, saya akan mempertimbangkan pola strategi:
Dimana Permintaan mewakili beberapa jenis DAO (panggilan balik dalam kasus sepele).
Kasus yang benar:
Kasus palsu:
Biasanya, implementasi titik akhir akan dikonfigurasikan pada tingkat abstraksi yang lebih tinggi dan saya hanya akan menggunakannya di sini. Sebagai efek samping gratis yang bermanfaat, ini memberi saya opsi untuk menerapkan cara lain untuk mengakses data jarak jauh, tanpa mengubah kode:
Secara umum, inversi kontrol semacam itu memastikan sambungan yang lebih rendah antara penyimpanan data dan model Anda.
sumber