Bagaimana saya bisa memformat ulang kondisi saya untuk membuatnya lebih baik?


35

Saya memiliki suatu kondisi

if(exists && !isDirectory || !exists)
{}

bagaimana saya bisa memodifikasinya, sehingga bisa lebih dimengerti.


1
nilai apa yang dimiliki isDirectory ketika ada salah?
marktani

1
ada adalah tipe Bool, isDirectory juga variabel tipe BOOL
Spynet

5
if (! isDirectory) ... (exist ||! exist) akan selalu benar.
Shark

@ Hiu - Bagaimana jika existsdan isDirectorykeduanya benar?
pasawaya

Saya membaca judul sebagai "Saya memiliki masalah kepribadian, dapatkah saya menghapus pikiran saya untuk memperbaikinya". Ya, saya lelah.
Annan

Jawaban:


110

|| komutatif begitu

if(!exists || (exists && !isDirectory))

setara.

Sekarang karena ada selalu benar di bagian kedua ||Anda dapat menjatuhkan &&:

if(!exists || !isDirectory)

Atau Anda dapat melangkah lebih jauh dan melakukan:

if(!(exists && isDirectory))

5
Apa yang tersirat tetapi tidak secara eksplisit disebutkan di sini adalah yang &&memiliki prioritas lebih tinggi (setidaknya dalam sebagian besar bahasa terkenal - mungkin ada pengecualian) daripada ||. Jadi a && b || csama dengan (a && b) || ctetapi tidak untuk a && (b || c).
Péter Török

27
Saya pikir, itu !exists || !isDirectorylebih "dapat dimengerti", karena, isDirectorytidak mungkin benar jika !exists. Jadi sebagai manusia kita akan mengatakan "jika itu tidak ada atau itu [ada dan itu] bukan direktori".
duros

6
Saya lebih suka! Ada || ! IsDirectory lebih dari yang terakhir.
Apoorv Khurasia

3
||hanya komutatif jika digunakan pada nilai tanpa efek samping - jika misalnya digunakan dengan fungsi, beberapa fungsi mungkin tidak dipanggil (hubungan arus pendek) atau mengembalikan nilai yang berbeda dalam urutan yang berbeda.
orlp

26
Siapa pun yang mengandalkan prioritas relatif dari '&&', '||', '==', '! =', Dll. Dan tidak memperjelas maksudnya dengan menggunakan tanda kurung layak untuk ditembak. Dalam semua bahasa, sesuatu seperti 'a && b || c 'setara dengan komentar yang mengatakan bahwa penulis mungkin mengacaukan semuanya untuk menghindari mengetik beberapa karakter tambahan.
Brendan

51

Sebagai suatu proses, saya sarankan membangun tabel kebenaran:

e = exists
d = isDirectory

e | d | (e && !d) || !e
--+---+----------------
0 | 0 | 1
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0

Ini cocok dengan NANDoperasi , yang hanya:

!(exists && isDirectory)

Jika Anda tidak mengingat semua gerbang logika Anda, wikipedia memiliki referensi yang bagus dengan tabel kebenaran untuk di-boot .


@Christoffer Hammarström mengemukakan satu poin penting tentang keadaan isDirectoryterikat pada keadaan exists. Dengan asumsi bahwa mereka merujuk ke referensi yang sama, dan bahwa tidak mungkin memiliki keadaan di mana referensi tidak ada dan merupakan direktori, tabel kebenaran dapat ditulis sebagai berikut:

e | d | (e && !d) || !e
--+---+----------------
0 | 0 | 1
0 | 1 | n/a
1 | 0 | 1
1 | 1 | 0

Yang n/adigunakan untuk mewakili sebuah negara yang tidak peduli. Pengurangan yang dapat diterima dapat menghasilkan salah satu 1atau 0untuk negara bagian yang menghasilkan n/a.

Dengan pemikiran ini, !(exists && isDirectory)masih merupakan reduksi yang valid, menghasilkan 1for !e && d.

Namun, !isDirectorypengurangan akan jauh lebih sederhana, menghasilkan 0untuk !e && d.


4
Langkah selanjutnya adalah menyadari bahwa itu isDirectorytergantung pada exists. Keduanya tidak bisa berupa direktori dan tidak ada.
Christoffer Hammarström

@ChristofferHammarstrom, Di luar konteks Saya tidak dapat berasumsi bahwa variabel merujuk pada hal yang sama, tetapi itu adalah poin yang valid. Kolom hasil harus diisi dengan n/atempat-tempat di mana negara tidak mungkin untuk dicapai, dan persamaan berkurang sesuai.
zzzzBov

Nah, jika variabel merujuk pada dua konteks yang berbeda, maka mereka terlalu singkat dan perlu diganti namanya.
Christoffer Hammarström

Tetapi membangun tabel kebenaran dan mengevaluasinya adalah lengkap NP!
Thomas Eding

@ Thomas, saya punya dua kutipan untuk Anda, "Secara teori, teori dan praktik adalah sama; dalam praktiknya, tidak." dan "Optimalisasi prematur adalah akar dari semua kejahatan."
zzzzBov

22

Untuk keterbacaan yang lebih baik, saya suka mengekstraksi kondisi boolean ke metode:

if(fileNameUnused())
{...}

public boolean fileNameUnused() {
   return exists && !isDirectory || !exists;
}

Atau dengan nama metode yang lebih baik. Jika Anda dapat memberi nama metode ini dengan benar, pembaca kode Anda tidak perlu mencari tahu apa arti kondisi boolean.


+1 untuk mengatakan sesuatu tentang nama yang berguna. Tetapi di suatu tempat Anda harus memformat ulang kondisi.
Apoorv Khurasia

4
Alternatif yang tidak terlalu ekstrem, yang masih menunjukkan niat, adalah untuk menyebutkan kondisi yang digunakan:boolean fileNameUnused = !exists || !isDirectory; if (fileNameUnused) { doSomething(); }
Steven

8

Anda bisa mencoba untuk menyelesaikan kasus no-go dan menebus jika itu muncul.

while(someCondition) {

    if(exists && isDirectory)
        continue;
        // maybe "break", depends on what you're after.

        // the rest of the code
}

atau bahkan

function processFile(someFile)
{ 
    // ...
    if(exists && isDirectory)
       return false;
    // the rest of the code
    // ...
}

Tidak melanggar, melanjutkan, dan lebih dari satu pernyataan pengembalian dianggap kode bau?
Freiheit

8
@Freiheit Tergantung pada konteksnya. Kadang-kadang pernyataan pengembalian awal digunakan untuk mengurangi lekukan, sehingga meningkatkan keterbacaan.
marco-fiset

Jawaban terbaik - persyaratan rumit menghabiskan banyak waktu membaca dan memahaminya dengan akurat. Akibatnya sering "diambil sebagai dibaca" yang mengarah ke bug berbahaya.
mattnz

6

Anda bisa menggunakan tabel kebenaran seperti yang ditunjukkan. Langkah kedua bisa berupa peta KV untuk meminimalkan jumlah istilah.

Menggunakan hukum aljabar Boolean adalah pendekatan lain:

A = ada
B =! IsDirectory
! A =! Ada

&& = *
|| = +

[Sunting]
Transformasi yang lebih sederhana, karena operasi AND dan OR saling mendistribusikan:

ada &&! isDirectory || ! exist
= A * B +! A
= (A +! A) * (B +! A)
= 1 * (B +! A)
= B +! A
[/ Edit]

ada &&! isDirectory || ! exist
= A * B +! A
= A * B +! A * 1 // Identitas
= A * B +! A * (B + 1) // Annihilator
= A * B +! A * B +! A / / Distributivity and Identity
= B * (A +! A) +! A // Distributivity
= B * 1 +! A // Komplementasi 2
= B +! A // Identity
=! IsDirectory || ! ada

Atau dengan komplemen ganda (!! x = x):

A * B +! A
= !! (A * B +! A)
=! (! (A * B) * A)
=! ((! A +! B) * A)
=! (! A * A + ! B * A)
=! (0 +! B * A)
=! (! B * A)
= B +! A
=! IsDirectory || ! ada


1 untuk menggunakan aturan formal (saya tidak pernah berpikir bahwa saya akan melihat salah satunya setelah tahun pertama saya kuliah).
Nemanja Boric


5

Saya tidak suka menggunakan "!" ketika ada lebih dari satu syarat dalam ekspresi. Saya akan menambahkan baris kode agar lebih mudah dibaca.

doesNotExist = !exists;
isFile = exists && !isDirecotry;
if (isFile || doesNotExist) 
   {}

+1 Ini membuatnya lebih mudah dibaca sebagai "apakah ada file atau tidak ada" yang jauh lebih dekat dengan bahasa Inggris.
Phil

Ini adalah refactoring yang disebut Introduce Explaining Variable .
Eddie Gasparian

1

Seperti yang ditunjukkan sebelumnya, kondisinya dapat dikurangi menjadi:

if (!(exists && isDirectory))

Namun, saya berani bertaruh bahwa menjadi direktori berarti keberadaan. Jika demikian, kita dapat mengurangi kondisinya menjadi:

if (!isDirectory)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.