Saya menemukan diri saya menulis banyak kode seperti ini:
int myFunction(Person* person) {
int personIsValid = !(person==NULL);
if (personIsValid) {
// do some stuff; might be lengthy
int myresult = whatever;
return myResult;
}
else {
return -1;
}
}
Ini bisa menjadi sangat berantakan, terutama jika beberapa cek terlibat. Dalam kasus seperti itu, saya telah bereksperimen dengan gaya alternatif, seperti yang ini:
int netWorth(Person* person) {
if (Person==NULL) {
return -1;
}
if (!(person->isAlive)) {
return -1;
}
int assets = person->assets;
if (assets==-1) {
return -1;
}
int liabilities = person->liabilities;
if (liabilities==-1) {
return -1;
}
return assets - liabilities;
}
Saya tertarik pada komentar tentang pilihan gaya di sini. [Jangan terlalu khawatir tentang perincian pernyataan individu; itu adalah aliran kontrol keseluruhan yang menarik minat saya.]
coding-style
language-agnostic
William Jockusch
sumber
sumber
Jawaban:
Untuk masalah seperti ini Martin Fowler mengusulkan Pola spesifikasi :
Di atas kedengarannya agak tinggi-alis (setidaknya bagi saya), tetapi ketika saya mencobanya dalam kode saya itu berjalan cukup lancar dan ternyata mudah diimplementasikan dan dibaca.
Cara saya melihatnya, ide utama adalah "mengekstrak" kode yang melakukan pemeriksaan ke dalam metode / objek khusus.
Dengan
netWorth
contoh Anda , ini bisa terlihat sebagai berikut:Kasing Anda terlihat agak sederhana sehingga semua cek terlihat OK untuk masuk dalam daftar polos dalam satu metode. Saya sering harus membagi lebih banyak metode untuk membuatnya lebih baik membaca.
Saya juga biasanya mengelompokkan / mengekstrak "spec" metode terkait dalam objek khusus, meskipun kasing Anda terlihat oke tanpa itu.
Pertanyaan ini di Stack Overflow merekomendasikan beberapa tautan selain yang disebutkan di atas: Contoh Pola Spesifikasi . Secara khusus, jawaban menyarankan Dimecasts 'Mempelajari Pola Spesifikasi' untuk panduan contoh dan menyebutkan makalah "Spesifikasi" yang ditulis oleh Eric Evans dan Martin Fowler .
sumber
Saya merasa lebih mudah untuk memindahkan validasi ke fungsinya sendiri, ini membantu menjaga maksud fungsi lainnya lebih bersih, jadi contoh Anda akan seperti ini.
sumber
if
dalamnyavalidPerson
? Cukup kembaliperson!=NULL && person->isAlive && person->assets !=-1 && person->liabilities != -1
saja.Satu hal yang saya lihat berhasil dengan baik adalah memperkenalkan lapisan validasi ke dalam kode Anda. Pertama, Anda memiliki metode yang melakukan semua validasi yang berantakan dan mengembalikan kesalahan (seperti
-1
dalam contoh Anda di atas) ketika terjadi kesalahan. Ketika validasi selesai, fungsi memanggil fungsi lain untuk melakukan pekerjaan yang sebenarnya. Sekarang fungsi ini tidak perlu melakukan semua langkah validasi itu karena sudah harus dilakukan. Artinya, fungsi kerja mengasumsikan bahwa input tersebut valid. Bagaimana seharusnya Anda menangani asumsi? Anda menegaskannya dalam kode.Saya pikir ini membuat kodenya sangat mudah dibaca. Metode validasi berisi semua kode berantakan untuk menangani kesalahan di sisi pengguna. Metode kerja dengan bersih mendokumentasikan asumsi dengan penegasan dan kemudian tidak harus bekerja dengan data yang berpotensi tidak valid.
Pertimbangkan refactoring dari contoh Anda ini:
sumber