Saya mencoba mengikuti saran kode bersih Paman Bob dan secara khusus membuat metode singkat.
Saya menemukan diri saya tidak dapat mempersingkat logika ini:
if (checkCondition()) {addAlert(1);}
else if (checkCondition2()) {addAlert(2);}
else if (checkCondition3()) {addAlert(3);}
else if (checkCondition4()) {addAlert(4);}
Saya tidak dapat menghapus elses dan dengan demikian memisahkan semuanya menjadi bit yang lebih kecil, menyebabkan "lain" di "lain jika" membantu kinerja - mengevaluasi kondisi tersebut mahal dan jika saya dapat menghindari mengevaluasi kondisi di bawah ini, menyebabkan salah satu yang pertama itu benar, saya ingin menghindarinya.
Bahkan secara semantik, mengevaluasi kondisi berikutnya jika sebelumnya dipenuhi tidak masuk akal dari sudut pandang bisnis.
sunting: Pertanyaan ini diidentifikasi sebagai duplikat dari cara-cara yang elegan untuk menangani if (if else) .
Saya percaya ini adalah pertanyaan yang berbeda (Anda dapat melihatnya juga dengan membandingkan jawaban dari pertanyaan-pertanyaan itu).
- Pertanyaan saya adalah memeriksa kondisi penerimaan pertama berakhir dengan cepat .
- Pertanyaan yang ditautkan adalah mencoba agar semua persyaratan dapat diterima untuk melakukan sesuatu. (lebih baik dilihat dalam jawaban untuk pertanyaan itu: https://softwareengineering.stackexchange.com/a/122625/96955 )
sumber
Jawaban:
Idealnya saya pikir Anda harus mengekstrak logika Anda untuk mendapatkan kode / nomor peringatan ke dalam metode sendiri. Jadi kode Anda yang ada berkurang hingga
dan Anda memiliki GetConditionCode () merangkum logika untuk memeriksa kondisi. Mungkin juga lebih baik menggunakan Enum daripada angka ajaib.
sumber
addAlert
perlu memeriksa kondisi peringatan palsuAlertCode.None
.Pengukuran penting adalah kompleksitas kode, bukan ukuran absolut. Dengan asumsi bahwa kondisi yang berbeda benar-benar hanya panggilan fungsi tunggal, sama seperti tindakan tidak lebih kompleks dari apa yang Anda tunjukkan, saya akan mengatakan tidak ada yang salah dengan kode. Ini sudah sesederhana mungkin.
Setiap upaya untuk "menyederhanakan" lebih lanjut memang akan memperumit masalah.
Tentu saja, Anda dapat mengganti
else
kata kunci denganreturn
seperti yang disarankan orang lain, tetapi itu hanya masalah gaya, bukan perubahan dalam kompleksitas apa pun.Ke samping:
Saran umum saya adalah, jangan pernah menjadi religius tentang aturan apa pun untuk kode bersih: Sebagian besar saran pengkodean yang Anda lihat di internet baik jika diterapkan dalam konteks yang sesuai, tetapi menerapkan secara radikal bahwa saran yang sama di mana-mana dapat membuat Anda mendapatkan entri di yang IOCCC . Caranya adalah selalu untuk mencapai keseimbangan yang memungkinkan manusia untuk dengan mudah beralasan tentang kode Anda.
Gunakan metode yang terlalu besar, dan Anda kacau. Gunakan fungsi terlalu kecil, dan Anda kacau. Hindari ekspresi ternary, dan Anda kacau. Gunakan ekspresi ternary di mana-mana, dan Anda kacau. Sadarilah bahwa ada tempat-tempat yang memanggil fungsi-fungsi satu jalur, dan tempat-tempat yang memanggil fungsi 50-saluran (ya, mereka ada!). Sadarilah bahwa ada tempat yang membutuhkan
if()
pernyataan, dan ada tempat yang meminta?:
operator. Gunakan gudang senjata lengkap yang Anda inginkan, dan cobalah untuk selalu menggunakan alat paling pas yang bisa Anda temukan. Dan ingat, jangan menjadi religius tentang nasihat ini juga.sumber
else if
dengan bagian dalamreturn
diikuti oleh sederhanaif
(menghapuselse
) mungkin membuat kode lebih sulit dibaca . Ketika kode mengatakanelse if
, saya langsung tahu bahwa kode di blok berikutnya hanya akan pernah dijalankan jika yang sebelumnya tidak. Tanpa muss, tidak repot. Jika itu polosif
maka mungkin dieksekusi atau mungkin tidak, terlepas dari apakah yang sebelumnya dieksekusi. Sekarang saya harus mengeluarkan sejumlah upaya mental untuk mengurai blok sebelumnya untuk mencatat bahwa itu berakhir dengan areturn
. Saya lebih suka menghabiskan upaya mental pada parsing logika bisnis.else if
membentuk satu unit semantik. (Ini belum tentu satu unit ke kompiler, tapi tidak apa-apa.)...; return; } if (...
Tidak; apalagi jika itu tersebar di beberapa baris. Itu adalah sesuatu yang saya harus benar-benar melihat untuk melihat apa yang dilakukannya, daripada bisa menerimanya secara langsung hanya dengan melihat pasangan kata kuncielse if
.else if
konstruksinya, terutama karena bentuknya dirantai adalah pola yang terkenal. Namun, kode formulirif(...) return ...;
juga merupakan pola yang terkenal, jadi saya tidak akan sepenuhnya mengutuk itu. Saya melihat ini benar-benar sebagai masalah kecil: Logika aliran kontrol adalah sama dalam kedua kasus, dan satu melihat lebih dekat padaif(...) { ...; return; }
tangga akan memberitahu saya bahwa itu memang setara denganelse if
tangga. Saya melihat struktur satu istilah, saya menyimpulkan artinya, saya menyadari bahwa itu diulang di mana-mana, dan saya tahu ada apa.else if
danreturn
. misalnyaelse if(...) { return alert();}
Sangat kontroversial apakah ini 'lebih baik' dari pada yang biasa jika ... lupakan kasus yang ada. Tetapi jika Anda ingin mencoba sesuatu yang lain, ini adalah cara yang umum untuk melakukannya.
Masukkan kondisi Anda dalam objek dan masukkan objek-objek itu dalam daftar
Jika diperlukan beberapa tindakan dengan syarat Anda dapat melakukan rekursi gila
Jelas ya. Ini hanya berfungsi jika Anda memiliki pola pada logika Anda. Jika Anda mencoba untuk membuat tindakan kondisional rekursif super generik maka setup untuk objek akan serumit seperti pernyataan if asli. Anda akan menciptakan bahasa / kerangka kerja baru Anda sendiri.
Tetapi teladan Anda memang memiliki pola
Kasus penggunaan umum untuk pola ini adalah validasi. Dari pada :
Menjadi
sumber
if...else
tangga ke dalam konstruksiConditions
daftar. Keuntungan bersih negatif, karena pembangunanConditions
akan mengambil kode sebanyak kode OP, tetapi tipuan tambahan datang dengan biaya dalam keterbacaan. Saya pasti lebih suka tangga kode yang bersih.conditions
dibangun ... ARG! Bukan atribut-anotasi! Oh Tuhan, kenapa? Ow mataku!Pertimbangkan untuk menggunakan
return;
setelah satu kondisi berhasil, itu akan menyelamatkan Anda semuaelse
. Anda bahkan mungkin dapatreturn addAlert(1)
secara langsung jika metode itu memiliki nilai balik.sumber
if
... Itu mungkin asumsi yang masuk akal, dan sekali lagi mungkin tidak.Saya telah melihat konstruksi seperti ini terkadang dianggap lebih bersih:
Ternary dengan spasi yang tepat juga bisa menjadi alternatif yang rapi:
Saya kira Anda juga bisa mencoba membuat array dengan pasangan yang berisi kondisi dan fungsi dan beralih di atasnya sampai kondisi pertama terpenuhi - yang seperti yang saya lihat akan sama dengan jawaban pertama Ewan.
sumber
case
label?Sebagai varian dari jawaban @ Ewan, Anda dapat membuat rantai (alih-alih "daftar datar") dari kondisi seperti ini:
Dengan cara ini Anda dapat menerapkan kondisi Anda dalam urutan yang ditentukan dan infrastruktur (kelas abstrak yang ditunjukkan) melewatkan cek yang tersisa setelah yang pertama telah dipenuhi.
Di sinilah lebih unggul daripada pendekatan "daftar datar" di mana Anda harus menerapkan "lewati" dalam loop yang menerapkan kondisi.
Anda cukup mengatur rantai kondisi:
Dan mulai evaluasi dengan panggilan sederhana:
sumber
Pertama-tama, kode asli bukan IMO yang mengerikan. Ini cukup dimengerti dan tidak ada yang buruk secara inheren di dalamnya.
Kemudian jika Anda tidak suka, bangunlah ide @ Ewan untuk menggunakan daftar tetapi menghapus
foreach break
pola yang agak tidak wajar :Sekarang sesuaikan ini dalam bahasa pilihan Anda, jadikan masing-masing elemen daftar objek, tupel, apa pun, dan Anda baik-baik saja.
EDIT: sepertinya tidak sejelas yang saya pikir, jadi izinkan saya menjelaskan lebih lanjut.
conditions
adalah daftar yang diurutkan atau semacamnya;head
adalah elemen saat ini sedang diselidiki - pada awalnya itu adalah elemen pertama dari daftar, dan setiap kalinext()
disebut itu menjadi yang berikut;check()
danalert()
adalahcheckConditionX()
danaddAlert(X)
dari OP.sumber
while not
bukanforeach break
.Pertanyaannya kurang spesifik. Jika kondisinya:
atau jika isinya
addAlert
lebih rumit, maka solusi yang mungkin lebih baik di katakanlah c # adalah:Tuples tidak begitu cantik di c # <8, tetapi dipilih untuk kenyamanan.
Pro dengan metode ini, bahkan jika tidak ada opsi di atas yang berlaku, adalah bahwa struktur diketik secara statis. Anda tidak dapat secara tidak sengaja mengacaukan, katakanlah, melewatkan sebuah
else
.sumber
Cara terbaik untuk mengurangi kompleksitas Siklomatik dalam kasus di mana Anda memiliki banyak
if->then statements
adalah dengan menggunakan kamus atau daftar (tergantung bahasa) untuk menyimpan nilai kunci (jika nilai pernyataan atau beberapa nilai) dan kemudian hasil nilai / fungsi.Misalnya, alih-alih (C #):
Saya bisa saja
Jika Anda menggunakan bahasa yang lebih modern Anda dapat menyimpan lebih banyak logika kemudian cukup nilai juga (c #). Ini benar-benar hanya fungsi sebaris, tetapi Anda juga bisa hanya menunjuk ke fungsi lain juga jika logikanya adalah untuk menempatkan secara in-line.
sumber
Kode Anda sudah terlalu pendek, tetapi logikanya sendiri tidak boleh diubah. Pada pandangan pertama sepertinya Anda mengulangi diri Anda dengan empat panggilan
checkCondition()
, dan itu hanya jelas bahwa masing-masing berbeda setelah membaca ulang kode dengan hati-hati. Anda harus menambahkan nama pemformatan dan fungsi yang tepat, misalnya:Kode Anda harus dapat dibaca di atas segalanya. Setelah membaca beberapa buku Paman Bob, saya percaya itu adalah pesan yang secara konsisten ia coba sampaikan.
sumber
Misalkan semua fungsi diimplementasikan dalam komponen yang sama, Anda bisa membuat fungsi mempertahankan beberapa negara untuk menyingkirkan beberapa cabang dalam aliran.
EG:
checkCondition1()
akan menjadievaluateCondition1()
, di mana ia akan memeriksa apakah kondisi sebelumnya terpenuhi; jika demikian, maka cache beberapa nilai untuk diambil olehgetConditionNumber()
.checkCondition2()
akan menjadievaluateCondition2()
, di mana ia akan memeriksa apakah kondisi sebelumnya terpenuhi. Jika kondisi sebelumnya tidak terpenuhi, maka memeriksa kondisi skenario 2, menyimpan nilai yang akan diambilgetConditionNumber()
. Dan seterusnya.SUNTING:
Berikut adalah cara memeriksa kondisi yang mahal perlu diterapkan agar pendekatan ini berhasil.
Oleh karena itu, jika Anda memiliki terlalu banyak pemeriksaan mahal untuk dilakukan, dan hal-hal dalam kode ini tetap pribadi, pendekatan ini membantu mempertahankannya, memungkinkan untuk mengubah urutan pemeriksaan jika perlu.
Jawaban ini hanya memberikan beberapa saran alternatif dari jawaban yang lain, dan mungkin tidak akan lebih baik dari kode asli jika kita anggap hanya 4 baris kode. Meskipun, ini bukan pendekatan yang mengerikan (dan tidak ada yang membuat pemeliharaan lebih sulit seperti yang dikatakan orang lain) mengingat skenario yang saya sebutkan (terlalu banyak pemeriksaan, hanya fungsi utama yang ditampilkan sebagai publik, semua fungsi adalah rincian implementasi dari kelas yang sama).
sumber
anyCondition() != false
.true
, OP tidak ingin kondisi 3 dievaluasi.anyCondition() != false
fungsievaluateConditionXX()
. Ini mungkin untuk diterapkan. Jika pendekatan menggunakan keadaan internal tidak diinginkan saya mengerti, tetapi argumen bahwa ini tidak berhasil tidak valid.Adakah lebih dari dua klausul "lain" memaksa pembaca kode untuk menelusuri seluruh rantai untuk menemukan yang menarik. Gunakan metode seperti: void AlertUponCondition (Kondisi kondisi) {switch (kondisi) {case Condition.Con1: ... break; kondisi case.Con2: ... istirahat; dll ...} Di mana "Kondisi" adalah enum yang tepat. Jika perlu, kembalikan bool atau nilai. Sebut saja seperti ini: AlertOnCondition (GetCondition ());
Ini benar-benar tidak bisa lebih sederhana, DAN itu lebih cepat daripada rantai if-else setelah Anda melebihi beberapa kasus.
sumber
Saya tidak dapat berbicara untuk situasi khusus Anda karena kode ini tidak spesifik, tetapi ...
kode seperti itu sering menjadi bau bagi model OO yang kurang. Anda benar-benar memiliki empat jenis hal, masing-masing terkait dengan jenis alerternya sendiri, tetapi alih-alih mengenali entitas ini dan membuat instance kelas untuk masing-masing, Anda memperlakukannya sebagai satu hal dan mencoba menebusnya nanti, pada saat Anda benar-benar perlu tahu apa yang Anda hadapi untuk melanjutkan.
Polimorfisme mungkin lebih cocok untuk Anda.
Curiga terhadap kode dengan metode panjang yang berisi konstruksi panjang atau rumit jika-maka. Anda sering menginginkan pohon kelas di sana dengan beberapa metode virtual.
sumber