Jika kita berasumsi bahwa tidak diinginkan untuk kelas dasar untuk menjadi kelas antarmuka murni, dan menggunakan 2 contoh dari bawah, yang merupakan pendekatan yang lebih baik, menggunakan definisi kelas metode abstrak atau virtual?
Keuntungan dari versi "abstrak" adalah bahwa ia mungkin terlihat lebih bersih dan memaksa kelas turunan untuk memberikan implementasi yang penuh harapan.
Keuntungan dari versi "virtual" adalah dapat dengan mudah ditarik oleh modul lain dan digunakan untuk pengujian tanpa menambahkan banyak kerangka dasar seperti yang dibutuhkan versi abstrak.
Versi Abstrak:
public abstract class AbstractVersion
{
public abstract ReturnType Method1();
public abstract ReturnType Method2();
.
.
public abstract ReturnType MethodN();
//////////////////////////////////////////////
// Other class implementation stuff is here
//////////////////////////////////////////////
}
Versi Virtual:
public class VirtualVersion
{
public virtual ReturnType Method1()
{
return ReturnType.NotImplemented;
}
public virtual ReturnType Method2()
{
return ReturnType.NotImplemented;
}
.
.
public virtual ReturnType MethodN()
{
return ReturnType.NotImplemented;
}
//////////////////////////////////////////////
// Other class implementation stuff is here
//////////////////////////////////////////////
}
return ReturnType.NotImplemented
? Serius? Jika Anda tidak dapat menolak jenis yang tidak diterapkan pada waktu kompilasi (Anda dapat; menggunakan metode abstrak) setidaknya melemparkan pengecualian.Jawaban:
Pilihan saya, jika saya mengkonsumsi barang-barang Anda, akan menjadi metode abstrak. Itu sejalan dengan "gagal lebih awal." Mungkin menyakitkan pada waktu deklarasi untuk menambahkan semua metode (meskipun alat refactoring yang layak akan melakukan ini dengan cepat), tetapi setidaknya saya tahu apa masalahnya segera dan memperbaikinya. Saya lebih suka daripada melakukan debug 6 bulan dan perubahan 12 orang nanti untuk melihat mengapa kita tiba-tiba mendapatkan pengecualian yang tidak diterapkan.
sumber
Versi virtualnya rawan bug dan secara semantik salah.
Abstrak mengatakan "metode ini tidak diterapkan di sini. Anda harus menerapkannya untuk membuat kelas ini berfungsi"
Virtual mengatakan "Saya memiliki implementasi default tetapi Anda dapat mengubah saya jika Anda perlu"
Jika tujuan akhir Anda adalah testabilitas maka antarmuka biasanya merupakan pilihan terbaik. (kelas ini melakukan x daripada kelas ini adalah kapak). Anda mungkin perlu memecah kelas menjadi beberapa komponen yang lebih kecil agar ini berfungsi dengan baik.
sumber
Ini tergantung pada penggunaan kelas Anda.
Jika metode memiliki beberapa implementasi "kosong" yang masuk akal, Anda memiliki banyak metode dan Anda sering menimpa hanya beberapa dari mereka, kemudian menggunakan
virtual
metode masuk akal. MisalnyaExpressionVisitor
diimplementasikan dengan cara ini.Kalau tidak, saya pikir Anda harus menggunakan
abstract
metode.Idealnya, Anda seharusnya tidak memiliki metode yang tidak diterapkan, tetapi dalam beberapa kasus, itu adalah pendekatan terbaik. Tetapi jika Anda memutuskan untuk melakukan itu, metode tersebut harus membuang
NotImplementedException
, tidak mengembalikan nilai khusus.sumber
Saya menyarankan agar Anda mempertimbangkan kembali memiliki antarmuka terpisah yang didefinisikan yang mengimplementasikan kelas dasar Anda, dan kemudian Anda mengikuti pendekatan abstrak.
Kode gambar seperti ini:
Melakukan ini menyelesaikan masalah ini:
Dengan memiliki semua kode yang menggunakan objek yang berasal dari AbstractVersion sekarang dapat diimplementasikan untuk menerima antarmuka IVersion, Ini berarti bahwa mereka dapat lebih mudah diuji unit.
Rilis 2 produk Anda kemudian dapat mengimplementasikan antarmuka IVersion2 untuk memberikan fungsionalitas tambahan tanpa melanggar kode pelanggan yang ada.
misalnya.
Juga patut dibaca tentang inversi dependensi, untuk mencegah kelas ini mengandung dependensi kode keras yang mencegah pengujian unit yang efektif.
sumber
Ketergantungan injeksi bergantung pada antarmuka. Inilah contoh singkat. Siswa Kelas memiliki fungsi yang disebut CreateStudent yang memerlukan parameter yang mengimplementasikan antarmuka "IReporting" (dengan metode ReportAction). Setelah membuat siswa, ia memanggil ReportAction pada parameter kelas beton. Jika sistem diatur untuk mengirim email setelah membuat siswa, kami mengirim kelas konkret yang mengirim email dalam implementasi ReportAction-nya, atau kami bisa mengirim kelas konkret lain yang mengirimkan output ke printer dalam implementasi ReportAction-nya. Bagus untuk digunakan kembali kode.
sumber