Saya membaca di posting blog ini tentang anti-pola anti-jika, dan saya tidak yakin saya mengerti mengapa ini anti-pola.
foreach (string filename in Directory.GetFiles("."))
{
if (filename.Equals("desktop.ini", StringComparison.OrdinalIgnoreCase))
{
return new StreamReader(filename);
}
}
Pertanyaan 1:
Apakah karena return new StreamReader(filename);
di dalam for loop
? atau fakta bahwa Anda tidak memerlukan for
loop dalam kasus ini?
Sebagai penulis blog menunjukkan versi kurang gila dari ini adalah:
if (File.Exists("desktop.ini"))
{
return new StreamReader("desktop.ini");
}
keduanya menderita kondisi balapan karena jika file dihapus sebelum pembuatan StreamReader
, Anda akan mendapatkan FileNotFoundException
.
Pertanyaan 2:
Untuk memperbaiki contoh kedua, apakah Anda akan menulis ulang tanpa pernyataan if, dan bukannya mengelilingi StreamReader
dengan blok try-catch, dan jika itu melempar FileNotFoundException
Anda menangani di catch
blok sesuai?
To fix the second example, would you re-write it without the if statement, and instead surround the StreamReader with a try-catch block, and if it throws a FileNotFoundException you handle it in the catch block accordingly?
- Ya, itulah yang akan saya lakukan. Memecahkan kondisi balapan lebih penting daripada beberapa gagasan "pengecualian sebagai aliran kontrol," dan menyelesaikannya dengan elegan dan bersih.null
? Anda biasanya dapat menggunakan LINQ untuk membersihkan kode yang terlihat seperti kode contoh Anda:return Directory.GetFiles(".").FirstOrDefault(fileName => fileName.Equals("desktop.ini", StringComparison.OrdinalIgnoreCase))?.Select(fileName => new StreamReader(filename));
Perhatikan?.
operator di antara dua panggilan LINQ. Juga orang mungkin berpendapat bahwa pembuatan objek seperti ini bukan penggunaan LINQ yang paling tepat, tapi saya pikir tidak apa-apa di sini. Ini bukan jawaban untuk pertanyaan Anda, tetapi apakah menyimpang pada satu bagian dari itu.Jawaban:
Ini adalah antipattern karena mengambil bentuk:
dan bisa diganti dengan
Contoh klasik dari ini adalah kode seperti:
Ketika yang berikut ini berfungsi dengan baik:
Jika Anda menemukan diri Anda melakukan perulangan dan
if
atauswitch
, kemudian berhenti dan pikirkan apa yang Anda lakukan. Apakah Anda overcomplicating hal dan dapat seluruh loop dan tes hanya diganti dengan garis sederhana "lakukan saja". Namun kadang-kadang, Anda perlu melakukan loop itu (misalnya, lebih dari satu item cocok dengan satu syarat), dalam hal ini polanya baik-baik saja.Itulah mengapa ini merupakan anti-pola: dibutuhkan pola "loop and test" dan melecehkannya.
Mengenai pertanyaan kedua Anda: ya. Pola "coba lakukan" lebih kuat daripada pola "tes lalu lakukan" dalam situasi apa pun di mana kode Anda bukan satu-satunya utas pada seluruh perangkat yang dapat mengubah status item yang diuji.
Masalah dengan kode ini:
adalah bahwa di antara waktu
File.Exists
danStreamReader
mencoba untuk membuka file itu, utas atau proses lain dapat menghapus file. Jadi, Anda akan mendapatkan pengecualian. Karena itu pengecualian itu harus dijaga melalui sesuatu seperti:@Flater memunculkan poin yang bagus? Apakah ini sendiri merupakan antipattern? Apakah kita menggunakan pengecualian sebagai aliran kontrol?
Jika kode membaca sesuatu seperti:
maka saya memang akan menggunakan pengecualian sebagai kebanggaan yang dimuliakan dan itu memang akan menjadi anti-pola. Tetapi dalam kasus ini kami hanya mengatasi perilaku yang tidak diinginkan dalam menciptakan aliran baru, jadi ini bukan contoh dari pola anti itu. Tetapi ini adalah contoh dari mengatasi anti-pola itu.
Tentu saja, yang benar-benar kita inginkan adalah cara yang lebih elegan untuk menciptakan aliran. Sesuatu seperti:
Dan saya sarankan membungkus
try catch
kode itu dalam metode utilitas seperti ini jika Anda sering menggunakan kode ini.sumber
Try
, misalnyareturn Try(() => new StreamReader("desktop.ini")).OrElse(null);
, tetapi C # tidak mendukung konstruk itu (tanpa menggunakan perpustakaan pihak ke-3), jadi kami harus bekerja dengan versi kikuk.File.Open
akan membuangnya jika tidak dapat menemukan file. Karena kita sudah memiliki pengecualian yang tidak biasa yang dilemparkan, menjebaknya sebagai bagian dari aliran kontrol adalah suatu keharusan (kecuali seseorang ingin membiarkan aplikasi itu crash).Maybe<Stream>
jenis yang mengembalikannothing
jika file tidak ada dan aliran jika itu.Ya, karena Anda tidak perlu melakukan pencarian sendiri untuk item yang disimpan dalam subsistem yang dapat ditanyakan.
Dalam abstrak, sistem file, seperti database, mampu merespons permintaan. Saat berinteraksi dengan subsistem yang dapat ditelusuri, kami memiliki pilihan mendasar, apakah kami ingin subsistem tersebut untuk menyebutkan isinya kepada kami agar kami dapat melakukan pencocokan di luar subsistem, atau menggunakan kemampuan kueri asli subsistem.
Mari kita berpura-pura sejenak bahwa Anda sedang mencari catatan dalam database daripada file dalam direktori di sistem file. Apakah Anda lebih suka melihat
dan kemudian dalam loop (misalnya dalam C #) di atas kursor yang dikembalikan mencari ID = 100, atau membiarkan subsistem yang dapat diminta melakukan apa yang dapat dilakukan untuk menemukan apa yang Anda cari?
Saya harus berpikir bahwa sebagian besar dari kita akan memilih untuk membiarkan subsistem melakukan permintaan yang tepat. Alternatif ini melibatkan beberapa perjalanan bolak-balik yang berpotensi dengan subsistem, pengujian kesetaraan yang tidak efisien, dan menghentikan penggunaan indeks atau akselerator pencarian lainnya, yang disediakan baik oleh basis data dan sistem file.
Ya, karena itulah cara API tertentu bekerja - sebenarnya bukan pilihan kami karena ini adalah fungsi perpustakaan. Pemeriksaan if, sebelum panggilan, tidak memberikan nilai tambahan: kita harus tetap menggunakan try / catch, karena (1) kesalahan lain di luar FileNotFound dapat terjadi, dan (2) kondisi balapan.
sumber
Streamreader tidak ada hubungannya dengan itu. Anti-pola muncul karena konflik niat yang jelas antara
foreach
danif
:Apa tujuan dari
foreach
?Saya berasumsi jawaban Anda akan seperti: "Saya ingin berulang kali mengeksekusi kode tertentu"
Berapa banyak file yang Anda harapkan diproses?
Karena Anda hanya dapat memiliki satu nama file tertentu (termasuk ekstensi) di folder tertentu, ini membuktikan bahwa kode Anda dimaksudkan untuk menemukan satu file yang berlaku.
Ini juga dikonfirmasi oleh fakta bahwa Anda segera mengembalikan nilai. Anda sebenarnya tidak peduli dengan pertandingan kedua, bahkan jika itu ada.
Ada situasi di mana ini bukan anti-pola.
Directory.GetFiles(".", SearchOption.AllDirectories)
), maka dimungkinkan untuk menemukan lebih dari satu file dengan nama file yang sama (termasuk ekstensi)"Test_"
, atau setiap"*.zip"
file.Perhatikan bahwa kedua kasus ini mengharuskan Anda untuk benar-benar memproses beberapa pertandingan dan karenanya tidak segera mengembalikan nilai.
Pengecualian itu mahal. Mereka tidak boleh digunakan sebagai pengganti logika aliran yang tepat. Pengecualian, seperti namanya menunjukkan keadaan luar biasa .
Karena alasan itu, Anda tidak boleh menghapus
if
.Sesuai jawaban ini di SoftwareEngineering.SE :
Sebagai ringkasan singkat mengapa, pada umumnya, ini merupakan anti-pola:
Apakah Anda perlu membungkus ini dalam percobaan / tangkapan, sangat tergantung pada situasi Anda:
Tidak ada yang pernah menjadi masalah "selalu gunakan itu". Untuk membuktikan maksud saya:
Jadi mengapa kita tidak memakai peralatan keselamatan ini setiap saat?
Jawaban sederhana adalah karena ada kekurangan untuk memakainya:
Sekarang kita berada di suatu tempat: ada pro dan kontra . Dengan kata lain, masuk akal untuk memakai peralatan ini dalam kasus di mana pro lebih besar daripada kontra.
Haruskah Anda membungkus panggilan dengan mencoba / menangkap? Itu sangat tergantung pada apakah manfaat melakukan itu lebih besar daripada biaya pelaksanaannya.
Perhatikan bahwa orang lain mungkin berpendapat bahwa hanya perlu beberapa penekanan tombol untuk membungkusnya, jadi itu jelas harus dilakukan. Tapi itu bukan keseluruhan argumen:
Jadi pilihan ada di tangan Anda. Apakah ada manfaatnya? Apakah Anda pikir itu meningkatkan aplikasi, lebih dari upaya biaya untuk mengimplementasikannya?
sumber