"Kelas abstrak" dan "antarmuka" adalah konsep yang serupa, dengan antarmuka menjadi lebih abstrak dari keduanya. Salah satu faktor pembeda adalah bahwa kelas abstrak menyediakan implementasi metode untuk kelas turunan saat dibutuhkan. Namun dalam C #, faktor pembeda ini telah dikurangi dengan pengenalan metode ekstensi baru-baru ini, yang memungkinkan implementasi disediakan untuk metode antarmuka. Faktor pembeda lainnya adalah bahwa suatu kelas dapat mewarisi hanya satu kelas abstrak (yaitu, tidak ada pewarisan berganda), tetapi dapat menerapkan banyak antarmuka. Ini membuat antarmuka menjadi kurang ketat dan lebih fleksibel. Jadi, di C #, kapan kita harus menggunakan kelas abstrak alih-alih antarmuka dengan metode ekstensi?
Contoh penting dari model metode antarmuka + ekstensi adalah LINQ, di mana fungsionalitas kueri disediakan untuk semua jenis yang mengimplementasikan IEnumerable
melalui banyak metode ekstensi.
sumber
Jawaban:
Ketika Anda membutuhkan bagian dari kelas untuk diimplementasikan. Contoh terbaik yang saya gunakan adalah pola metode templat .
Dengan demikian, Anda dapat menentukan langkah-langkah yang akan diambil ketika Do () dipanggil, tanpa mengetahui secara spesifik bagaimana mereka akan dilaksanakan. Turunan kelas harus menerapkan metode abstrak, tetapi bukan metode Do ().
Metode ekstensi tidak harus memenuhi bagian "harus menjadi bagian dari kelas" dari persamaan. Selain itu, iirc, metode ekstensi tidak bisa (nampak) seperti ruang publik.
sunting
Pertanyaannya lebih menarik daripada yang saya berikan pada awalnya. Setelah pemeriksaan lebih lanjut, Jon Skeet menjawab pertanyaan seperti ini di SO yang mendukung penggunaan antarmuka + metode ekstensi. Juga, potensi downside menggunakan refleksi terhadap hierarki objek yang dirancang dengan cara ini.
Secara pribadi, saya mengalami kesulitan melihat manfaat dari mengubah praktik yang umum saat ini, tetapi juga melihat beberapa kelemahan dalam melakukannya.
Perlu dicatat bahwa dimungkinkan untuk memprogram dengan cara ini dalam banyak bahasa melalui kelas Utility. Ekstensi hanya menyediakan gula sintaksis untuk membuat metode terlihat seperti milik kelas.
sumber
Do()
akan didefinisikan sebagai metode ekstensi. Dan metode yang tersisa untuk definisi kelas turunan sepertiDoThis()
akan menjadi anggota Antarmuka utama. Dan dengan antarmuka, Anda dapat mendukung banyak implementasi / warisan. Dan lihat ini- odetocode.com/blogs/scott/archive/2009/10/05/…Ini semua tentang apa yang ingin Anda modelkan:
Kelas abstrak bekerja berdasarkan pewarisan . Menjadi kelas dasar khusus, mereka memodelkan beberapa hubungan -a .
Sebagai contoh, seekor anjing adalah binatang, demikianlah yang kita miliki
Karena tidak masuk akal untuk benar-benar membuat generik semua-hewan (seperti apa bentuknya?), Kami membuat
Animal
kelas dasar iniabstract
- tetapi ini masih merupakan kelas dasar. DanDog
kelas tidak masuk akal tanpa menjadiAnimal
.Antarmuka di sisi lain adalah cerita yang berbeda. Mereka tidak menggunakan warisan tetapi memberikan polimorfisme (yang juga dapat diterapkan dengan warisan). Mereka tidak mencontoh hubungan is-a , tetapi lebih dari itu memang mendukung .
Ambil mis
IComparable
- objek yang mendukung dibandingkan dengan yang lain .Fungsionalitas suatu kelas tidak tergantung pada antarmuka yang diterapkannya, antarmuka hanya menyediakan cara umum untuk mengakses fungsionalitas. Kita masih bisa
Dispose
denganGraphics
atauFileStream
tanpa menerapkannyaIDisposable
. The antarmuka hanya berkaitan metode bersama-sama.Pada prinsipnya, seseorang dapat menambah dan menghapus antarmuka seperti halnya ekstensi tanpa mengubah perilaku suatu kelas, hanya memperkaya aksesnya. Anda tidak bisa mengambil kelas dasar karena objek akan menjadi tidak berarti!
sumber
Animal
abstrak. Ini memungkinkan Anda untuk menulisabstract
fungsi yang akan dikhususkan oleh kelas turunan. Atau lebih dalam hal pemrograman - itu mungkin tidak masuk akal untuk membuatUserControl
, tetapi sebagaiButton
adalah sebuahUserControl
, jadi kami memiliki jenis yang sama dari hubungan kelas / baseclass.Saya baru menyadari, bahwa saya belum pernah menggunakan kelas abstrak (setidaknya tidak dibuat) selama bertahun-tahun.
Kelas abstrak adalah binatang yang agak aneh antara antarmuka dan implementasi. Ada sesuatu di kelas abstrak yang menggelitik spider-sense saya. Saya berpendapat, orang tidak boleh "mengekspos" implementasi di balik antarmuka dengan cara apa pun (atau membuat tie-in).
Bahkan jika ada kebutuhan untuk perilaku umum antara kelas yang mengimplementasikan suatu antarmuka, saya akan menggunakan kelas pembantu independen, bukan kelas abstrak.
Saya akan pergi untuk antarmuka.
sumber
IMHO, saya pikir ada perpaduan konsep di sini.
Kelas menggunakan jenis warisan tertentu, sedangkan antarmuka menggunakan jenis warisan yang berbeda.
Kedua jenis warisan itu penting dan bermanfaat, dan masing-masing memiliki pro dan kontra.
Mari kita mulai dari awal.
Kisah dengan antarmuka dimulai sejak lama dengan C ++. Pada pertengahan 1980-an, ketika C ++ dikembangkan, gagasan antarmuka sebagai jenis yang berbeda belum terwujud (ini akan datang tepat waktu).
C ++ hanya memiliki satu jenis warisan, jenis warisan yang digunakan oleh kelas, yang disebut warisan implementasi.
Untuk dapat menerapkan rekomendasi Buku GoF: "Untuk memprogram untuk antarmuka, dan bukan untuk implementasi", C ++ mendukung kelas abstrak dan banyak warisan implementasi untuk dapat melakukan apa yang dapat dilakukan oleh antarmuka di C # (dan berguna!) Untuk melakukan .
C # memperkenalkan jenis baru jenis, antarmuka, dan jenis baru warisan, antarmuka antarmuka, untuk menawarkan setidaknya dua cara berbeda untuk mendukung "Memprogram untuk antarmuka, dan bukan untuk implementasi", dengan satu peringatan penting: C # saja mendukung multiple inheritance dengan inheritance antarmuka (dan bukan dengan inheritance implementasi).
Jadi, alasan arsitektur di balik antarmuka di C # adalah rekomendasi GoF.
Saya harap ini bisa membantu.
Salam, Gaston
sumber
Menerapkan metode ekstensi ke antarmuka berguna untuk menerapkan perilaku umum di seluruh kelas yang mungkin hanya berbagi antarmuka umum. Kelas semacam itu mungkin sudah ada dan ditutup untuk ekstensi melalui cara lain.
Untuk desain baru saya lebih suka menggunakan metode ekstensi pada antarmuka. Untuk hierarki Jenis, metode ekstensi menyediakan cara untuk memperluas perilaku tanpa harus membuka seluruh hierarki untuk modifikasi.
Namun, metode ekstensi tidak dapat mengakses implementasi pribadi, jadi di puncak hierarki, jika saya perlu merangkum implementasi swasta di belakang antarmuka publik maka kelas abstrak akan menjadi satu-satunya cara.
sumber
Saya pikir di C # multiple inheritance tidak didukung dan itu sebabnya konsep antarmuka diperkenalkan di C #.
Dalam kasus kelas abstrak, multiple inheritance juga tidak didukung. Jadi mudah untuk memutuskan apakah akan menggunakan kelas atau antarmuka abstrak.
sumber
Saya sedang dalam proses mengimplementasikan kelas abstrak di proyek saya hanya karena C # tidak mendukung operator (konversi implisit, dalam kasus saya) di Antarmuka.
sumber