Ada satu perbedaan kecil antara Java dan C # yang relevan di sini. Di Jawa, setiap anggota adalah virtual secara default. Dalam C #, setiap anggota disegel secara default - kecuali untuk anggota antarmuka.
Asumsi yang sesuai dengan pedoman ini memengaruhi - di Jawa, setiap tipe publik harus dianggap non-final, sesuai dengan Prinsip Pergantian Liskov [1]. Jika Anda hanya memiliki satu implementasi, Anda akan memberi nama kelas Parser
; jika Anda membutuhkan beberapa implementasi, Anda hanya akan mengubah kelas menjadi antarmuka dengan nama yang sama, dan mengganti nama implementasi konkret menjadi sesuatu yang deskriptif.
Dalam C #, asumsi utama adalah bahwa ketika Anda mendapatkan kelas (nama tidak dimulai dengan I
), itulah kelas yang Anda inginkan. Pikiran Anda, ini tidak mendekati 100% akurat - contoh-contoh khas akan menjadi kelas seperti Stream
(yang seharusnya merupakan antarmuka, atau beberapa antarmuka), dan setiap orang memiliki panduan dan latar belakang mereka sendiri dari bahasa lain. Ada juga pengecualian lain seperti Base
sufiks yang cukup banyak digunakan untuk menunjukkan kelas abstrak - seperti halnya dengan antarmuka, Anda tahu jenisnya seharusnya polimorfik.
Ada juga fitur kegunaan yang bagus dalam membiarkan nama non-I-awalan untuk fungsi yang berhubungan dengan antarmuka itu tanpa harus menggunakan membuat antarmuka kelas abstrak (yang akan merugikan karena kurangnya kelas multiple-inheritance di C #). Ini dipopulerkan oleh LINQ, yang digunakan IEnumerable<T>
sebagai antarmuka, dan Enumerable
sebagai tempat penyimpanan metode yang berlaku untuk antarmuka itu. Ini tidak perlu di Java, di mana antarmuka dapat berisi implementasi metode juga.
Pada akhirnya, I
awalan secara luas digunakan di dunia C #, dan dengan ekstensi, dunia .NET (karena sejauh ini sebagian besar. Kode NET ditulis dalam C #, masuk akal untuk mengikuti pedoman C # untuk sebagian besar antarmuka publik). Ini berarti Anda hampir pasti akan bekerja dengan perpustakaan dan kode yang mengikuti notasi ini, dan masuk akal untuk mengadopsi tradisi untuk mencegah kebingungan yang tidak perlu - tidak seperti menghilangkan awalan akan membuat kode Anda lebih baik :)
Saya berasumsi bahwa alasan Paman Bob adalah sesuatu seperti ini:
IBanana
adalah gagasan abstrak pisang. Jika ada kelas pelaksana yang tidak memiliki nama yang lebih baik dari itu Banana
, abstraksi sama sekali tidak berarti, dan Anda harus meninggalkan antarmuka dan hanya menggunakan kelas. Jika ada nama yang lebih baik (katakanlah, LongBanana
atau AppleBanana
), tidak ada alasan untuk tidak menggunakan Banana
nama antarmuka. Oleh karena itu, menggunakan I
awalan menandakan bahwa Anda memiliki abstraksi yang tidak berguna, yang membuat kode lebih sulit untuk dipahami tanpa manfaat. Dan karena OOP yang ketat akan membuat Anda selalu kode terhadap antarmuka, satu-satunya tempat di mana Anda tidak akan melihat I
awalan pada suatu jenis akan berada di konstruktor - kebisingan yang tidak ada gunanya.
Jika Anda menerapkan ini pada IParser
antarmuka sampel Anda, Anda dapat dengan jelas melihat bahwa abstraksi sepenuhnya berada di wilayah "tidak berarti". Entah ada sesuatu yang spesifik tentang implementasi konkret dari parser (misalnya JsonParser
, XmlParser
, ...), atau Anda hanya harus menggunakan kelas. Tidak ada yang namanya "implementasi default" (meskipun di beberapa lingkungan, ini memang masuk akal - terutama, COM), baik ada implementasi spesifik, atau Anda ingin kelas abstrak atau metode ekstensi untuk "default". Namun, dalam C #, kecuali basis kode Anda sudah menghapus I
-prefix, simpan. Buat catatan mental setiap kali Anda melihat kode class Something: ISomething
- artinya seseorang tidak pandai mengikuti YAGNI dan membangun abstraksi yang masuk akal.
[1] - Secara teknis, ini tidak secara khusus disebutkan dalam makalah Liskov, tetapi ini adalah salah satu dasar dari kertas OOP asli dan dalam pembacaan saya tentang Liskov, dia tidak menentang ini. Dalam interpretasi yang kurang ketat (yang diambil oleh sebagian besar bahasa OOP), ini berarti bahwa setiap kode yang menggunakan tipe publik yang dimaksudkan untuk substitusi (yaitu non-final / disegel) harus bekerja dengan implementasi yang sesuai dari tipe tersebut.