It's sesuatu yang's disadap saya dalam setiap bahasa I've digunakan, saya memiliki jika pernyataan tapi bersyarat bagian memiliki begitu banyak pemeriksaan yang harus saya membaginya atas beberapa baris, menggunakan nested if pernyataan atau hanya menerima bahwa itu's jelek dan melanjutkan dengan hidup saya.
Apakah ada metode lain yang anda've ditemukan yang mungkin berguna bagi saya dan orang lain yang's kena masalah yang sama?
Contoh, semua dalam satu baris:
if (var1 = true && var2 = true && var2 = true && var3 = true && var4 = true && var5 = true && var6 = true)
{
Contoh, multi-line:
if (var1 = true && var2 = true && var2 = true
&& var3 = true && var4 = true && var5 = true
&& var6 = true)
{
Contoh-bersarang:
if (var1 = true && var2 = true && var2 = true && var3 = true)
{
if (var4 = true && var5 = true && var6 = true)
{
Terpisah, kondisi di beberapa boolean dan kemudian menggunakan master boolean sebagai kondisi.
bool isOpaque = object.Alpha == 1.0f;
bool isDrawable = object.CanDraw && object.Layer == currentLayer;
bool isHidden = hideList.Find(object);
bool isVisible = isOpaque && isDrawable && ! isHidden;
if(isVisible)
{
// ...
}
Lebih baik lagi:
public bool IsVisible {
get
{
bool isOpaque = object.Alpha == 1.0f;
bool isDrawable = object.CanDraw && object.Layer == currentLayer;
bool isHidden = hideList.Find(object);
return isOpaque && isDrawable && ! isHidden;
}
}
void Draw()
{
if(IsVisible)
{
// ...
}
}
Pastikan anda memberikan nama variabel yang sebenarnya menunjukkan niat daripada fungsi. Ini akan sangat membantu pengembang menjaga kode anda... bisa jadi ANDA!
I'm terkejut tidak ada yang punya yang satu ini belum. Ada's refactoring khusus untuk jenis masalah:
http://www.refactoring.com/catalog/decomposeConditional.html
Ada dua masalah ke alamat berikut: mudah dibaca dan dimengerti
&Quot;mudah dibaca" solusi masalah gaya dan terbuka untuk interpretasi. Preferensi saya adalah ini:
if (var1 == true && // Explanation of the check
var2 == true && // Explanation of the check
var3 == true && // Explanation of the check
var4 == true && // Explanation of the check
var5 == true && // Explanation of the check
var6 == true) // Explanation of the check
{ }
atau ini:
if (var1 && // Explanation of the check
var2 && // Explanation of the check
var3 && // Explanation of the check
var4 && // Explanation of the check
var5 && // Explanation of the check
var6) // Explanation of the check
{ }
Yang mengatakan, ini semacam kompleks cek dapat cukup sulit untuk mental mengurai saat memindai kode (terutama jika anda bukan penulis asli). Pertimbangkan untuk membuat sebuah metode pembantu untuk abstrak beberapa kompleksitas jauh:
/// <Summary>
/// Tests whether all the conditions are appropriately met
/// </Summary>
private bool AreAllConditionsMet (
bool var1,
bool var2,
bool var3,
bool var4,
bool var5,
bool var6)
{
return (
var1 && // Explanation of the check
var2 && // Explanation of the check
var3 && // Explanation of the check
var4 && // Explanation of the check
var5 && // Explanation of the check
var6); // Explanation of the check
}
private void SomeMethod()
{
// Do some stuff (including declare the required variables)
if (AreAllConditionsMet (var1, var2, var3, var4, var5, var6))
{
// Do something
}
}
Sekarang ketika visual scanning "SomeMethod" metode, sebenarnya kompleksitas tes logika tersembunyi tetapi makna semantik yang diawetkan bagi manusia untuk memahami pada tingkat tinggi. Jika pengembang benar-benar perlu untuk memahami rincian, AreAllConditionsMet metode yang dapat diperiksa.
Ini secara resmi dikenal sebagai "Terurai Bersyarat" refactoring pola yang saya pikirkan. Alat-alat seperti Resharper atau Refactor Pro! dapat membuat melakukan semacam ini refactoring mudah!
Dalam semua kasus, kunci untuk memiliki dibaca dan dimengerti kode untuk menggunakan realistis nama-nama variabel. Sementara saya memahami ini adalah contoh yang dibuat-buat, "var1", "var2", dll tidak nama-nama variabel yang dapat diterima. Mereka harus memiliki nama yang mencerminkan sifat dasar dari data yang mereka wakili.
I'll sering membagi ini menjadi komponen variabel boolean:
bool orderValid = orderDate < DateTime.Now && orderStatus != Status.Canceled;
bool custValid = customerBalance == 0 && customerName != "Mike";
if (orderValid && custValid)
{
...
Pertama, saya'd menghapus semua == true
bagian, yang akan membuatnya lebih pendek 50%;)
Ketika saya memiliki kondisi saya mencari alasan. Kadang-kadang saya melihat aku harus menggunakan polimorfisme, kadang-kadang saya perlu untuk menambahkan beberapa keadaan objek. Pada dasarnya, itu berarti refactoring yang dibutuhkan (kode bau).
Kadang-kadang saya gunakan De-Morgan's undang-undang untuk menyederhanakan ekspresi boolean sedikit.
Check out Implementasi Pola oleh Kent Beck. Ada pola tertentu saya berpikir itu dapat membantu dalam situasi ini... ini adalah yang disebut "Penjaga". Daripada memiliki ton kondisi, anda dapat istirahat mereka menjadi penjaga, yang membuat jelas yang merupakan kondisi yang merugikan dalam sebuah metode.
Jadi misalnya, jika anda memiliki sebuah metode yang melakukan sesuatu, tapi ada kondisi-kondisi tertentu di mana seharusnya't melakukan sesuatu, daripada:
public void doSomething() {
if (condition1 && condition2 && condition3 && condition4) {
// do something
}
}
Anda bisa mengubahnya ke:
public void doSomething() {
if (!condition1) {
return;
}
if (!condition2) {
return;
}
if (!condition3) {
return;
}
if (!condition4) {
return;
}
// do something
}
It's sedikit lebih panjang, tapi lebih banyak dibaca, terutama ketika anda mulai memiliki aneh bersarang, penjaga dapat membantu (dikombinasikan dengan ekstraksi metode).
Saya SANGAT merekomendasikan buku itu dengan cara.
I've melihat banyak orang dan editor baik indentasi masing-masing kondisi anda jika pernyataan dengan salah satu tab, atau pencocokan itu dengan terbuka paren:
if (var1 == true
&& var2 == true
&& var3 == true
) {
/* do something.. */
}
Saya biasanya menempatkan paren dekat pada baris yang sama seperti kondisi terakhir:
if (var1 == true
&& var2 == true
&& var3 == true) {
/* do something.. */
}
Tapi aku don't pikir ini cukup bersih.
Coba cari di Functors dan Predikat. Apache Commons proyek memiliki sebuah set objek untuk memungkinkan anda untuk merangkum logika kondisional menjadi objek. Contoh penggunaannya adalah tersedia di O'reilly di sini. Kutipan dari contoh kode:
import org.apache.commons.collections.ClosureUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.functors.NOPClosure;
Map predicateMap = new HashMap();
predicateMap.put( isHonorRoll, addToHonorRoll );
predicateMap.put( isProblem, flagForAttention );
predicateMap.put( null, ClosureUtils.nopClosure() );
Closure processStudents =
ClosureUtils.switchClosure( predicateMap );
CollectionUtils.forAllDo( allStudents, processStudents );
Sekarang rincian dari semua orang isHonorRoll predikat dan penutupan yang digunakan untuk mengevaluasi mereka:
import org.apache.commons.collections.Closure;
import org.apache.commons.collections.Predicate;
// Anonymous Predicate that decides if a student
// has made the honor roll.
Predicate isHonorRoll = new Predicate() {
public boolean evaluate(Object object) {
Student s = (Student) object;
return( ( s.getGrade().equals( "A" ) ) ||
( s.getGrade().equals( "B" ) &&
s.getAttendance() == PERFECT ) );
}
};
// Anonymous Predicate that decides if a student
// has a problem.
Predicate isProblem = new Predicate() {
public boolean evaluate(Object object) {
Student s = (Student) object;
return ( ( s.getGrade().equals( "D" ) ||
s.getGrade().equals( "F" ) ) ||
s.getStatus() == SUSPENDED );
}
};
// Anonymous Closure that adds a student to the
// honor roll
Closure addToHonorRoll = new Closure() {
public void execute(Object object) {
Student s = (Student) object;
// Add an award to student record
s.addAward( "honor roll", 2005 );
Database.saveStudent( s );
}
};
// Anonymous Closure flags a student for attention
Closure flagForAttention = new Closure() {
public void execute(Object object) {
Student s = (Student) object;
// Flag student for special attention
s.addNote( "talk to student", 2005 );
s.addNote( "meeting with parents", 2005 );
Database.saveStudent( s );
}
};
Steve Mcconell's saran, dari Kode Lengkap: Menggunakan multi-dimensi tabel. Masing-masing variabel berfungsi sebagai indeks untuk tabel, dan jika ternyata pernyataan ke dalam tabel lookup. Misalnya if (ukuran == 3 && berat badan > 70) diterjemahkan ke dalam tabel entry keputusan[size][weight_group]
Nah, pertama, mengapa tidak:
jika (var1 && var2 && var2 && var3 && var4 && var5 && var6) { ...
Juga, it's sangat sulit untuk refactor abstrak kode contoh. Jika anda menunjukkan sebuah contoh spesifik akan lebih mudah untuk mengidentifikasi baik pola agar sesuai dengan masalah.
It's tidak baik, tapi apa yang saya've dilakukan di masa lalu: (Berikut metode mencegah hubungan arus pendek boolean pengujian, semua tes berjalan bahkan jika yang pertama adalah palsu. Tidak dianjurkan pola kecuali anda tahu yang anda butuhkan untuk selalu melaksanakan semua kode sebelum kembali -- Terima kasih untuk ptomato untuk bercak kesalahan saya!)
<menyerang>Yang sama dengan:</strike> (tidak sama, lihat catatan di atas!)boolean ok = cond1; ok &= cond2; ok &= cond3; ok &= cond4; ok &= cond5; ok &= cond6;
ok = (cond1 && cond2 && cond3 && cond4 && cond5 && cond6);
if ( (condition_A)
&& (condition_B)
&& (condition_C)
&& (condition_D)
&& (condition_E)
&& (condition_F)
)
{
...
}
sebagai lawan
if (condition_A) {
if (condition_B) {
if (condition_C) {
if (condition_D) {
if (condition_E) {
if (condition_F) {
...
}
}
}
}
}
}
dan
if ( ( (condition_A)
&& (condition_B)
)
|| ( (condition_C)
&& (condition_D)
)
|| ( (condition_E)
&& (condition_F)
)
)
{
do_this_same_thing();
}
sebagai lawan
if (condition_A && condition_B) {
do_this_same_thing();
}
if (condition_C && (condition_D) {
do_this_same_thing();
}
if (condition_E && condition_F) {
do_this_same_thing();
}
Sebagian besar statis alat analisis untuk memeriksa kode akan mengeluh jika beberapa ekspresi kondisional tidak menggunakan eksplisit kurung mendikte analisis ekspresi, bukan mengandalkan operator didahulukan aturan dan kurang tanda kurung.
Alinyemen vertikal pada saat yang sama indent tingkat buka/tutup kurung kurawal {}, buka tutup kurung (), ekspresi kondisional dengan tanda kurung dan operator di sebelah kiri adalah aplikasi yang sangat berguna praktek, yang sangat MENINGKATKAN keterbacaan dan kejelasan kode sebagai lawan untuk jamming segala sesuatu yang mungkin dapat menjadi macet ke satu baris, sans vertikal keselarasan, spasi atau tanda kurung
Operator precedence aturan yang rumit, misalnya && memiliki lebih diutamakan dari | | tapi | telah didahulukan dari &&
Jadi, ...
if (expr_A & expr_B || expr_C | expr_D & expr_E || expr_E && expr_F & expr_G || expr_H {
}
ini benar-benar mudah beberapa ekspresi kondisional untuk sekedar manusia untuk membaca dan mengevaluasi dengan benar.
if ( ( (expr_A)
& (expr_B)
)
|| ( (expr_C)
| ( (expr_D)
& (expr_E)
)
)
|| ( (expr_E)
&& ( (expr_F)
& (expr_G)
)
)
|| (expr_H)
)
{
}
Tidak ada yang salah dengan ruang horisontal (linefeeds), perataan vertikal, atau eksplisit kurung membimbing evaluasi ekspresi, semua yang MENINGKATKAN keterbacaan dan kejelasan
Aku ingin istirahat mereka turun tingkat, jadi saya'd format anda contoh seperti ini:
if (var1 = true
&& var2 = true
&& var2 = true
&& var3 = true
&& var4 = true
&& var5 = true
&& var6 = true){
It's sangat berguna ketika anda memiliki lebih banyak bersarang, seperti ini (jelas kondisi nyata akan lebih menarik dari "= true" untuk semuanya):
if ((var1 = true && var2 = true)
&& ((var2 = true && var3 = true)
&& (var4 = true && var5 = true))
&& (var6 = true)){
Jika anda kebetulan menjadi pemrograman Python, it's menang dengan built-in semua()
fungsi diterapkan atas daftar variabel (I'll hanya menggunakan Boolean literals di sini):
>>> L = [True, True, True, False, True]
>>> all(L) # True, only if all elements of L are True.
False
>>> any(L) # True, if any elements of L are True.
True
Apakah ada fungsi yang sesuai dalam bahasa anda (C#? Jawa?). Jika demikian, yang's mungkin terbersih pendekatan.
McDowell,
Anda benar bahwa ketika menggunakan single '&' operator bahwa kedua belah pihak ekspresi mengevaluasi. Namun, ketika menggunakan '&&' operator (setidaknya di C#) itulah ekspresi pertama untuk kembali palsu adalah yang terakhir ekspresi dievaluasi. Ini membuat menempatkan evaulation sebelum pernyataan hanya sebagai baik sebagai cara lain untuk melakukan itu.
@tweakt
It's tidak baik, tapi apa yang saya've dilakukan di masa lalu:
boolean ok = cond1; ok &= cond2; ok &= cond3; ok &= cond4; ok &= cond5; ok &= cond6;
Yang sama seperti:
ok = (cond1 && cond2 && cond3 && cond4 && cond5 && cond6);
Sebenarnya, ini dua hal yang tidak sama dalam semua bahasa. Ekspresi kedua biasanya akan berhenti sedang dievaluasi sebagai segera sebagai salah satu syarat adalah palsu, yang bisa menjadi besar peningkatan kinerja jika mengevaluasi kondisi yang lebih mahal.
Untuk dibaca, saya pribadi lebih suka Mike Batu's proposal di atas. It's mudah untuk verbosely komentar dan mempertahankan semua komputasi karena bisa untuk awal keluar. Anda juga dapat melakukan teknik yang sama inline dalam suatu fungsi jika itu'd membingungkan organisasi dari kode anda untuk memindahkan bersyarat evaluasi jauh dari fungsi lainnya. It's bit cheesy, tapi anda selalu bisa melakukan sesuatu seperti:
do {
if (!cond1)
break;
if (!cond2)
break;
if (!cond3)
break;
...
DoSomething();
} while (false);
sementara (palsu) adalah jenis yang murahan. Saya berharap bahasa memiliki scoping operator yang disebut "sekali" atau sesuatu yang anda bisa keluar dengan mudah.
Aku ingin istirahat setiap kondisi dalam deskriptif variabel.
bool isVar1Valid, isVar2Valid, isVar3Valid, isVar4Valid;
isVar1Valid = ( var1 == 1 )
isVar2Valid = ( var2.Count >= 2 )
isVar3Valid = ( var3 != null )
isVar4Valid = ( var4 != null && var4.IsEmpty() == false )
if ( isVar1Valid && isVar2Valid && isVar3Valid && isVar4Valid ) {
//do code
}
Jika saya melakukan itu di Perl, Ini adalah bagaimana saya bisa menjalankan pemeriksaan.
{
last unless $var1;
last unless $var2;
last unless $var3;
last unless $var4;
last unless $var5;
last unless $var6;
... # Place Code Here
}
Jika anda berencana untuk menggunakan ini lebih dari sebuah subroutine ganti setiap instance dari terakhir
dengan kembali
;