Menurut Apakah salah menggunakan parameter boolean untuk menentukan perilaku? , Saya tahu pentingnya menghindari menggunakan parameter boolean untuk menentukan perilaku, misalnya:
versi asli
public void setState(boolean flag){
if(flag){
a();
}else{
b();
}
c();
}
versi baru:
public void setStateTrue(){
a();
c();
}
public void setStateFalse(){
b();
c();
}
Tetapi bagaimana dengan kasus bahwa parameter boolean digunakan untuk menentukan nilai alih-alih perilaku? misalnya:
public void setHint(boolean isHintOn){
this.layer1.visible=isHintOn;
this.layer2.visible=!isHintOn;
this.layer3.visible=isHintOn;
}
Saya mencoba menghilangkan flag isHintOn dan membuat 2 fungsi terpisah:
public void setHintOn(){
this.layer1.visible=true;
this.layer2.visible=false;
this.layer3.visible=true;
}
public void setHintOff(){
this.layer1.visible=false;
this.layer2.visible=true;
this.layer3.visible=false;
}
tetapi versi yang dimodifikasi tampaknya kurang dapat dipelihara karena:
ini memiliki lebih banyak kode daripada versi aslinya
tidak dapat dengan jelas menunjukkan bahwa visibilitas layer2 berlawanan dengan opsi petunjuk
ketika layer baru (mis .: layer4) ditambahkan, saya perlu menambahkan
this.layer4.visible=false;
dan
this.layer4.visible=true;
ke dalam setHintOn () dan setHintOff () secara terpisah
Jadi pertanyaan saya adalah, jika parameter boolean digunakan untuk menentukan nilai saja, tetapi bukan perilaku (misalnya: tidak ada jika-lain pada parameter itu), apakah masih disarankan untuk menghilangkan parameter boolean itu?
setHint(boolean isHintOn)
sebagai pribadi , dan tambahkan metode publiksetHintOn
dansetHintOff
yang masing-masing memanggilsetHint(true)
dansetHint(false)
.setHint(true|false)
. Potahto kentang. Setidaknya gunakan sesuatu sepertisetHint
danunsetHint
.is
di awal.isValid
dll. Jadi mengapa mengubahnya menjadi dua kata? Selain itu, "lebih alami" ada di mata yang melihatnya. Jika Anda ingin mengucapkannya sebagai kalimat bahasa Inggris, maka bagi saya akan lebih alami untuk memiliki "jika petunjuknya ada pada" dengan "yang" dimasukkan.Jawaban:
Desain API harus fokus pada apa yang paling bisa digunakan untuk klien API, dari sisi panggilan .
Misalnya, jika API baru ini mengharuskan penelepon untuk menulis kode secara teratur seperti ini
maka harus jelas bahwa menghindari parameter lebih buruk daripada memiliki API yang memungkinkan pemanggil untuk menulis
Versi sebelumnya hanya menghasilkan masalah yang kemudian harus diselesaikan di sisi panggilan (dan mungkin lebih dari sekali). Itu tidak meningkatkan keterbacaan atau pemeliharaan.
Sisi implementasi , bagaimanapun, seharusnya tidak menentukan bagaimana API publik terlihat. Jika fungsi seperti
setHint
dengan parameter membutuhkan lebih sedikit kode dalam implementasi, tetapi API dalam halsetHintOn
/setHintOff
terlihat lebih mudah digunakan untuk klien, orang dapat menerapkannya dengan cara ini:Jadi meskipun API publik tidak memiliki parameter boolean, tidak ada logika rangkap di sini, jadi hanya satu tempat untuk berubah ketika persyaratan baru (seperti dalam contoh pertanyaan) tiba.
Ini juga bekerja sebaliknya: jika
setState
metode dari atas perlu beralih di antara dua bagian kode yang berbeda, potongan-potongan kode itu dapat di-refactored ke dua metode pribadi yang berbeda. Jadi IMHO tidak masuk akal untuk mencari kriteria untuk memutuskan antara "satu parameter / satu metode" dan "nol parameter / dua metode" dengan melihat internal. Namun, perhatikan cara Anda ingin melihat API dalam peran konsumennya.Jika ragu, coba gunakan "test driven development" (TDD), yang akan memaksa Anda untuk memikirkan API publik dan bagaimana menggunakannya.
sumber
SetLoanFacility(bool enabled)
, karena setelah memberikan pinjaman, mungkin tidak mudah untuk membawanya lagi, dan dua opsi mungkin melibatkan logika yang sama sekali berbeda - dan Anda ingin pindah ke terpisah. Buat / Hapus metode.Toggle()
bukan fungsi yang benar untuk disediakan. Itulah intinya; jika penelepon hanya peduli tentang "ubah" dan bukan "apa yang berakhir dengan" makaToggle()
adalah opsi yang menghindari pemeriksaan tambahan dan pengambilan keputusan. Saya tidak akan menyebut bahwa itu kasus UMUM, saya juga tidak akan merekomendasikan membuatnya tersedia tanpa alasan yang baik, tetapi jika pengguna membutuhkan toggle maka saya akan memberi mereka toggle.Martin Fowler mengutip Kent Beck dalam merekomendasikan
setOn()
setOff()
metode terpisah , tetapi juga mengatakan bahwa ini tidak boleh dianggap tidak dapat diganggu gugat:Rekomendasi lain adalah dengan menggunakan nilai enumerasi atau tipe bendera untuk memberi
true
danfalse
lebih baik, nama spesifik konteks. Dalam contoh Anda,showHint
danhideHint
bisa lebih baik.sumber
-[NSView setNeedsDisplay:]
metode di mana Anda lulusYES
jika tampilan harus digambar ulang danNO
jika tidak. Anda hampir tidak perlu mengatakannya untuk tidak, jadi UIKit hanya memiliki-[UIView setNeedsDisplay]
tanpa parameter. Itu tidak memiliki-setDoesNotNeedDisplay
metode yang sesuai .bool isPremium
flag dalam contohnya, tetapi saya akan menggunakan enum (BookingType bookingType
) untuk parameterisasi metode yang sama, kecuali jika logika untuk setiap pemesanan cukup berbeda. "Logika kusut" yang dirujuk oleh Fowler seringkali diinginkan jika seseorang ingin dapat melihat apa perbedaan antara kedua mode. Dan jika mereka sangat berbeda, saya akan mengekspos metode parameterised secara eksternal, dan mengimplementasikan metode terpisah secara internal.Saya pikir Anda mencampur dua hal dalam posting Anda, API dan implementasinya. Dalam kedua kasus saya tidak berpikir ada aturan yang kuat yang dapat Anda gunakan sepanjang waktu, tetapi Anda harus mempertimbangkan dua hal ini secara mandiri (sebanyak mungkin).
Mari kita mulai dengan API, keduanya:
dan:
adalah alternatif yang valid tergantung pada objek yang seharusnya Anda tawarkan dan bagaimana klien Anda akan menggunakan API. Seperti yang ditunjukkan Doc, jika pengguna Anda sudah memiliki variabel Boolean (dari kontrol UI, aksi pengguna, eksternal, API, dll) opsi pertama lebih masuk akal, jika tidak, Anda hanya memaksakan pernyataan tambahan jika pernyataan pada kode klien . Namun, jika misalnya Anda mengubah petunjuk menjadi true saat memulai proses dan menjadi false di akhir opsi pertama memberi Anda sesuatu seperti ini:
sedangkan opsi kedua memberi Anda ini:
IMO mana yang jauh lebih mudah dibaca, jadi saya akan memilih opsi kedua dalam hal ini. Jelas, tidak ada yang menghentikan Anda dari menawarkan kedua opsi (atau lebih, Anda bisa menggunakan enum seperti kata Graham jika itu lebih masuk akal misalnya).
Intinya adalah Anda harus memilih API berdasarkan apa yang seharusnya dilakukan oleh objek dan bagaimana klien akan menggunakannya, bukan berdasarkan pada bagaimana Anda akan mengimplementasikannya.
Maka Anda harus memilih bagaimana Anda mengimplementasikan API publik Anda. Katakanlah kami memilih metode
setHintOn
dansetHintOff
sebagai API publik kami dan mereka membagikan logika umum ini seperti dalam contoh Anda. Anda dapat dengan mudah mengabstraksi logika ini melalui metode pribadi (kode disalin dari Doc):Sebaliknya, katakanlah kami memilih
setHint(boolean isHintOn)
API kami tetapi mari balikkan contoh Anda, karena alasan apa pun yang mengatur petunjuk On sama sekali berbeda dengan menyetelnya ke Off. Dalam hal ini kita bisa menerapkannya sebagai berikut:Atau bahkan:
Intinya adalah bahwa, dalam kedua kasus, kami pertama-tama memilih API publik kami dan kemudian mengadaptasi implementasi kami agar sesuai dengan API yang dipilih (dan kendala yang kami miliki), bukan sebaliknya.
Ngomong-ngomong, saya pikir hal yang sama berlaku untuk posting yang Anda tautkan tentang menggunakan parameter boolean untuk menentukan perilaku, yaitu Anda harus memutuskan berdasarkan pada use case khusus Anda daripada beberapa aturan keras (meskipun dalam kasus tertentu biasanya hal yang benar untuk dilakukan rusak dalam beberapa fungsi).
sumber
begin
danend
atau sinonim, hanya untuk membuatnya secara eksplisit menjelaskan apa yang mereka lakukan, dan untuk menyiratkan bahwa awal harus memiliki akhir dan sebaliknya.using
blok di C #,with
pernyataan konteks manajer dengan Python, meneruskan tubuh sebagai lambda atau objek yang dapat dipanggil (mis. sintaksis blok Ruby), dll.Hal pertama yang pertama: kode tidak secara otomatis kurang dapat dipelihara, hanya karena itu sedikit lebih lama. Kejelasan adalah yang terpenting.
Sekarang, jika Anda benar - benar hanya berurusan dengan data, maka apa yang Anda miliki adalah setter untuk properti boolean. Dalam hal ini Anda mungkin ingin hanya menyimpan nilai itu secara langsung dan mendapatkan visibilitas lapisan, yaitu
(Saya telah mengambil kebebasan untuk memberi layer nama sebenarnya - jika Anda tidak memiliki ini dalam kode asli Anda, saya akan mulai dengan itu)
Ini masih menyisakan pertanyaan apakah memiliki
setHintVisibility(bool)
metode. Secara pribadi, saya akan merekomendasikan menggantinya dengan metodeshowHint()
danhideHint()
- keduanya akan sangat sederhana dan Anda tidak perlu mengubahnya ketika Anda menambahkan lapisan. Namun, ini bukan pemotongan yang benar / salah.Sekarang jika memanggil fungsi seharusnya benar-benar mengubah visibilitas lapisan-lapisan itu, Anda sebenarnya memiliki perilaku. Dalam hal ini, saya pasti akan merekomendasikan metode terpisah.
sumber
showHint
vssetHintVisibility
). Saya menyebutkan layer baru hanya karena OP khawatir tentang hal itu. Juga, kita hanya perlu menambahkan satu metode baru:isLayer4Visible
.showHint
danhideHint
hanya mengaturisHintVisible
atribut ke true / false dan itu tidak berubah.Parameter Boolean baik-baik saja dalam contoh kedua. Seperti yang sudah Anda ketahui, parameter boolean tidak dengan sendirinya bermasalah. Ini mengubah perilaku berdasarkan pada bendera, yang bermasalah.
Contoh pertama bermasalah, karena penamaan menunjukkan metode setter, tetapi implementasi tampaknya menjadi sesuatu yang berbeda. Jadi, Anda memiliki antipattern switching perilaku, dan metode yang disebut menyesatkan. Tetapi jika metode ini sebenarnya adalah setter biasa (tanpa pergantian perilaku), maka tidak ada masalah dengan
setState(boolean)
. Memiliki dua metode,setStateTrue()
dansetStateFalse()
hanya hal-hal rumit yang tidak perlu tanpa manfaat.sumber
Cara lain untuk memecahkan masalah ini adalah dengan memperkenalkan objek untuk mewakili setiap petunjuk, dan membuat objek bertanggung jawab untuk menentukan nilai-nilai boolean yang terkait dengan petunjuk itu. Dengan cara ini Anda bisa menambahkan permutasi baru daripada hanya memiliki dua status boolean.
Misalnya, di Jawa, Anda dapat melakukan:
Dan kemudian kode penelepon Anda akan terlihat seperti ini:
Dan kode implementasi Anda akan terlihat seperti ini:
Hal ini membuat kode implementasi dan kode pemanggil ringkas, sebagai imbalan untuk mendefinisikan tipe data baru yang dengan jelas memetakan niat yang diketik dengan kuat, yang dinamai dengan set negara yang sesuai. Saya pikir itu lebih baik di sekitar.
sumber
Ketika saya memiliki keraguan tentang hal-hal seperti itu. Saya suka menggambarkan seperti apa jejak tumpukan itu.
Selama bertahun-tahun saya bekerja pada proyek PHP yang menggunakan fungsi yang sama dengan setter dan pengambil . Jika Anda lulus nol, itu akan mengembalikan nilai, jika tidak setel. Sangat mengerikan untuk bekerja dengannya .
Berikut ini contoh jejak tumpukan:
Anda tidak tahu keadaan internal dan itu membuat debugging lebih sulit. Ada banyak efek samping negatif lainnya, tetapi cobalah untuk melihat ada nilai dalam nama fungsi verbose dan kejelasan ketika fungsi melakukan satu tindakan.
Sekarang gambar bekerja dengan jejak stack untuk fungsi yang memiliki perilaku A atau B berdasarkan nilai boolean.
Itu membingungkan jika Anda bertanya kepada saya. Garis yang sama
setVisible
menghasilkan dua jalur jejak yang berbeda.Jadi kembalilah ke pertanyaan Anda. Coba gambarkan seperti apa jejak tumpukan itu, bagaimana komunikasinya kepada seseorang tentang apa yang terjadi dan tanyakan pada diri Anda apakah Anda membantu orang yang akan datang men-debug kode.
Berikut beberapa tips:
Terkadang kode terlihat berlebihan di bawah mikroskop, tetapi ketika Anda menarik kembali ke gambar yang lebih besar pendekatan minimalis akan membuatnya menghilang. Jika Anda perlu menonjol agar Anda dapat mempertahankannya. Menambahkan banyak fungsi kecil mungkin terasa terlalu bertele-tele, tetapi itu meningkatkan pemeliharaan ketika digunakan secara luas dalam konteks yang lebih besar.
sumber
setVisible
jejak stack adalah bahwa panggilansetVisible(true)
muncul menghasilkan panggilan kesetVisible(false)
(atau sebaliknya, tergantung pada bagaimana Anda membuat jejak itu terjadi).Di hampir setiap kasus di mana Anda mengirimkan
boolean
parameter ke metode sebagai bendera untuk mengubah perilaku sesuatu, Anda harus mempertimbangkan yang lebih eksplisit dan aman untuk melakukan hal ini.Jika Anda melakukan tidak lebih dari menggunakan
Enum
yang mewakili negara Anda telah meningkatkan pemahaman kode Anda.Contoh ini menggunakan
Node
kelas dariJavaFX
:selalu lebih baik daripada, seperti yang ditemukan pada banyak
JavaFX
objek:tapi saya pikir
.setVisible()
dan.setHidden()
merupakan solusi terbaik untuk situasi di mana bendera adalahboolean
karena ini adalah yang paling eksplisit dan paling tidak bertele-tele.dalam hal sesuatu dengan banyak pilihan, ini bahkan lebih penting untuk dilakukan dengan cara ini.
EnumSet
ada hanya karena alasan ini.sumber
Ketika memutuskan antara pendekatan untuk beberapa antarmuka yang melewati parameter (boolean) vs metode kelebihan beban tanpa parameter tersebut, lihat ke klien yang mengkonsumsi.
Jika semua penggunaan akan melewati nilai konstan (misalnya benar, salah) maka itu berpendapat untuk kelebihan.
Jika semua penggunaan akan melewati nilai variabel maka itu berargumen untuk metode dengan pendekatan parameter.
Jika tidak satu pun dari kedua ekstrem itu yang berlaku, itu berarti ada campuran penggunaan klien, jadi Anda harus memilih apakah akan mendukung kedua bentuk, atau membuat satu kategori klien untuk beradaptasi dengan yang lain (yang bagi mereka merupakan gaya yang lebih tidak wajar).
sumber
Ada dua pertimbangan untuk mendesain:
Mereka seharusnya tidak digabung.
Tidak apa-apa untuk:
Dengan demikian, argumen apa pun yang berusaha menyeimbangkan biaya / manfaat desain API dengan biaya / manfaat desain implementasi diragukan dan harus diperiksa dengan cermat.
Di sisi API
Sebagai seorang programmer, saya biasanya akan mendukung API yang dapat diprogram. Kode jauh lebih jelas ketika saya bisa meneruskan nilai daripada ketika saya membutuhkan
if
/switch
pernyataan pada nilai untuk memutuskan fungsi mana yang harus dipanggil.Yang terakhir mungkin diperlukan jika setiap fungsi mengharapkan argumen yang berbeda.
Jadi, dalam kasus Anda, satu metode
setState(type value)
tampak lebih baik.Namun , ada yang lebih buruk daripada tanpa nama
true
,false
,2
, dll ... nilai-nilai sihir tidak memiliki arti sendiri. Hindari obsesi primitif , dan merangkul ketikan yang kuat.Dengan demikian, dari API POV, saya ingin:
setState(State state)
.Di sisi implementasi
Saya sarankan melakukan apa pun yang lebih mudah.
Jika metodenya sederhana, sebaiknya tetap bersama. Jika aliran kontrol berbelit-belit, yang terbaik untuk memisahkannya dalam beberapa metode, masing-masing berurusan dengan sub-kasus atau langkah pipa.
Akhirnya, pertimbangkan pengelompokan .
Dalam contoh Anda (dengan spasi kosong yang dapat dibaca):
Mengapa
layer2
merusak tren? Apakah ini fitur atau bug?Mungkinkah memiliki 2 daftar
[layer1, layer3]
dan[layer2]
, dengan eksplisit nama menunjukkan alasan mereka dikelompokkan bersama, dan kemudian beralih ke daftar itu.Sebagai contoh:
Kode berbicara sendiri, jelas mengapa ada dua kelompok dan perilaku mereka berbeda.
sumber
Terpisah dari pertanyaan
setOn() + setOff()
vsset(flag)
, saya akan mempertimbangkan dengan hati-hati apakah jenis boolean terbaik di sini. Apakah Anda yakin tidak akan ada opsi ketiga?Mungkin lebih baik mempertimbangkan enum daripada boolean. Selain memungkinkan ekstensibilitas, ini juga mempersulit mendapatkan boolean dengan cara yang salah, misalnya:
vs.
Dengan enum, akan jauh lebih mudah untuk diperpanjang ketika seseorang memutuskan mereka menginginkan opsi 'jika diperlukan':
vs.
sumber
Saya akan menyarankan untuk mengevaluasi kembali pengetahuan ini.
Pertama-tama, saya tidak melihat kesimpulan yang Anda usulkan dalam pertanyaan SE yang Anda tautkan. Mereka kebanyakan berbicara tentang meneruskan parameter melalui beberapa langkah pemanggilan metode, di mana ia dievaluasi sangat jauh di rantai.
Dalam contoh Anda, Anda mengevaluasi parameter tepat di metode Anda. Dalam hal itu, tidak ada perbedaan sama sekali dari jenis parameter lainnya.
Secara umum, sama sekali tidak ada yang salah dengan menggunakan parameter boolean; dan tentu saja parameter apa pun akan menentukan perilaku, atau mengapa Anda harus memilikinya?
sumber
Mendefinisikan pertanyaan
Pertanyaan judul Anda adalah "Apakah salah dengan [...]?" - tapi apa maksudmu dengan "salah"?
Menurut kompiler C # atau Java, itu tidak salah. Saya yakin Anda sadar akan hal itu dan bukan itu yang Anda minta. Saya takut selain itu, kami hanya punya pendapat berbeda
n
programmern+1
. Jawaban ini menyajikan apa yang dikatakan buku Kode Bersih tentang hal ini.Menjawab
Kode Bersih membuat kasus yang kuat terhadap argumen fungsi secara umum:
"Pembaca" di sini bisa menjadi konsumen API. Ini juga bisa menjadi pembuat kode berikutnya, yang belum tahu apa yang kode ini lakukan - yang bisa Anda lakukan dalam sebulan. Mereka akan melalui 2 fungsi secara terpisah atau melalui 1 fungsi dua kali , sekali mengingat
true
dan sekalifalse
dalam pikiran.Singkatnya, gunakan argumen sesedikit mungkin .
Kasus spesifik argumen bendera kemudian ditangani secara langsung:
Untuk menjawab pertanyaan Anda secara langsung:
Menurut Clean Code , Disarankan untuk menghilangkan parameter itu.
Informasi tambahan:
Contoh Anda agak sederhana, tetapi bahkan di sana Anda dapat melihat kesederhanaan menyebar ke kode Anda: Fungsi tanpa-parameter hanya melakukan penugasan sederhana, sedangkan fungsi lainnya harus melakukan aritmatika boolean untuk mencapai tujuan yang sama. Ini adalah aritmatika boolean yang sepele dalam contoh sederhana ini, tetapi mungkin cukup rumit dalam situasi nyata.
Saya telah melihat banyak argumen di sini bahwa Anda harus membuatnya bergantung pada pengguna API, karena harus melakukan ini di banyak tempat akan menjadi bodoh:
Saya tidak setuju bahwa sesuatu yang non-optimal yang terjadi di sini. Mungkin terlalu jelas untuk dilihat, tetapi kalimat pertama Anda menyebutkan "pentingnya menghindari [sic] menggunakan parameter boolean untuk menentukan perilaku" dan itulah dasar untuk seluruh pertanyaan. Saya tidak melihat alasan untuk membuat hal yang buruk untuk dilakukan lebih mudah bagi pengguna API.
Saya tidak tahu apakah Anda melakukan pengujian - dalam hal ini, pertimbangkan juga ini:
sumber