Saya penggemar tulisan, kontrak, atau jenis cek apa pun yang tersedia dalam bahasa yang saya gunakan. Satu hal yang sedikit mengganggu saya adalah bahwa saya tidak yakin apa praktik umum untuk menangani cek duplikat.
Contoh situasi: Saya pertama-tama menulis fungsi berikut
void DoSomething( object obj )
{
Contract.Requires<ArgumentNullException>( obj != null );
//code using obj
}
kemudian beberapa jam kemudian saya menulis fungsi lain yang memanggil yang pertama. Karena semuanya masih segar dalam memori, saya memutuskan untuk tidak menduplikasi kontrak, karena saya tahu bahwa kita DoSomething
akan mengecek objek nol:
void DoSomethingElse( object obj )
{
//no Requires here: DoSomething will do that already
DoSomething( obj );
//code using obj
}
Masalah yang jelas: DoSomethingElse
sekarang tergantung pada DoSomething
untuk memverifikasi bahwa obj bukan nol. Jadi sebaiknya jangan DoSomething
pernah memutuskan untuk tidak memeriksa lagi, atau jika saya memutuskan untuk menggunakan fungsi lain, obj mungkin tidak diperiksa lagi. Yang membuat saya menulis implementasi ini:
void DoSomethingElse( object obj )
{
Contract.Requires<ArgumentNullException>( obj != null );
DoSomething( obj );
//code using obj
}
Selalu aman, jangan khawatir, kecuali bahwa jika situasinya tumbuh, objek yang sama mungkin diperiksa beberapa kali dan ini merupakan bentuk duplikasi dan kita semua tahu itu tidak begitu baik.
Apa praktik paling umum untuk situasi seperti ini?
sumber
ArgumentBullException
? Itu yang baru :)Jawaban:
Secara pribadi saya akan memeriksa nol dalam fungsi apa pun yang akan gagal jika mendapat nol, dan tidak dalam fungsi apa pun yang tidak.
Jadi, dalam contoh Anda di atas, jika doSomethingElse () tidak perlu dereference obj maka saya tidak akan memeriksa obj untuk null di sana.
Jika DoSomething () tidak keberatan dereference maka harus memeriksa nol.
Jika kedua fungsi dereferensi maka keduanya harus memeriksa. Jadi jika DoSomethingElse dereferences obj maka harus memeriksa nol, tetapi DoSomething juga masih harus memeriksa nol karena dapat dipanggil dari jalur lain.
Dengan cara ini Anda dapat membiarkan kode cukup bersih dan masih menjamin bahwa cek berada di tempat yang benar.
sumber
DoSomething()
sedemikian rupa sehingga prasyarat tidak lagi diperlukan (tidak mungkin dalam kasus khusus ini, tetapi mungkin terjadi dalam situasi yang berbeda), dan menghapus pemeriksaan prakondisi. Sekarang beberapa metode yang tampaknya sama sekali tidak berhubungan rusak karena prasyarat yang hilang. Saya akan mengambil sedikit duplikasi kode untuk kejelasan kegagalan aneh seperti itu dari keinginan untuk menyimpan beberapa baris kode, kapan saja.Bagus! Saya melihat Anda mengetahui tentang Kontrak Kode untuk .NET. Kontrak Kode berjalan lebih jauh dari pernyataan rata-rata Anda, di mana pemeriksa statis adalah contoh terbaik. Ini mungkin tidak tersedia untuk Anda jika Anda belum menginstal Visual Studio Premium atau lebih tinggi, tetapi penting untuk memahami maksud di baliknya jika Anda akan menggunakan Kontrak Kode.
Ketika Anda menerapkan kontrak ke suatu fungsi, itu secara harfiah adalah kontrak . Fungsi itu menjamin untuk berperilaku sesuai dengan kontrak, dan dijamin hanya akan digunakan sebagaimana didefinisikan oleh kontrak.
Dalam contoh yang Anda berikan,
DoSomethingElse()
fungsi tidak sesuai dengan kontrak seperti yang ditentukan olehDoSomething()
, karena nol dapat dilewati, dan pemeriksa statis akan menunjukkan masalah ini. Cara untuk menyelesaikan ini adalah dengan menambahkan kontrak yang sama keDoSomethingElse()
.Sekarang, ini berarti akan ada duplikasi, tetapi duplikasi ini diperlukan saat Anda memilih untuk mengekspos fungsionalitas di dua fungsi. Fungsi-fungsi ini, meskipun bersifat pribadi, dapat dipanggil dari tempat yang berbeda di kelas Anda juga, jadi satu-satunya cara untuk menjamin bahwa dari panggilan mana pun argumen tidak akan pernah batal adalah dengan menduplikasi kontrak.
Ini seharusnya membuat Anda mempertimbangkan kembali mengapa Anda membagi perilaku menjadi dua fungsi. Saya selalu berpendapat ( bertentangan dengan kepercayaan populer ) bahwa Anda tidak boleh membagi fungsi yang hanya dipanggil dari satu tempat . Dengan mengekspos enkapsulasi dengan menerapkan kontrak, ini menjadi lebih jelas. Sepertinya saya menemukan argumen tambahan untuk tujuan saya! Terima kasih! :)
sumber