Saya memiliki kelas dengan beberapa fungsi standar / bersama. Saya gunakan abstract class
untuk itu:
public interface ITypeNameMapper
{
string Map(TypeDefinition typeDefinition);
}
public abstract class TypeNameMapper : ITypeNameMapper
{
public virtual string Map(TypeDefinition typeDefinition)
{
if (typeDefinition is ClassDefinition classDefinition)
{
return Map(classDefinition);
}
...
throw new ArgumentOutOfRangeException(nameof(typeDefinition));
}
protected abstract string Map(ClassDefinition classDefinition);
}
Seperti yang Anda lihat, saya juga memiliki antarmuka ITypeNameMapper
. Apakah masuk akal untuk mendefinisikan antarmuka ini jika saya sudah memiliki kelas abstrak TypeNameMapper
atau abstract class
cukup?
TypeDefinition
dalam contoh minimal ini juga abstrak.
c#
interfaces
abstract-class
Konrad
sumber
sumber
Jawaban:
Ya, karena C # tidak mengizinkan banyak pewarisan kecuali dengan antarmuka.
Jadi jika saya memiliki kelas yang merupakan TypeNameMapper dan SomethingelseMapper saya bisa melakukannya:
sumber
ICanFly
,ICanRun
,ICanSwim
. Anda perlu membuat 8 kelas makhluk, satu untuk setiap kombinasi sifat (YYY, YYN, YNY, ..., NNY, NNN). SRP menyatakan bahwa Anda menerapkan setiap perilaku (terbang, lari, berenang) satu kali dan kemudian menerapkannya kembali pada 8 makhluk. Komposisi akan lebih baik di sini, tetapi mengabaikan komposisi sebentar, Anda seharusnya sudah melihat perlunya mewarisi / menerapkan beberapa perilaku yang dapat digunakan kembali secara terpisah karena SRP.interface
malapraktik formal craptacular .. implementasi berlebihan yang seharusnya ada di basis - yang berevolusi secara independen !, perubahan logika bersyarat yang mendorong sampah ini karena kekurangan metode templat, enkapsulasi rusak, abstraksi yang tidak ada. Favorit saya: 1-metode kelas masing-masing menerapkan 1-metode sendiriinterface
, masing-masing dengan hanya satu contoh. ... etc, etc, and etc.Antarmuka dan kelas abstrak melayani tujuan yang berbeda:
Dalam contoh Anda,
interface ITypeNameMapper
tentukan kebutuhan klien danabstract class TypeNameMapper
tidak menambah nilai apa pun.sumber
public
milik klien.TypeNameMapper
menambahkan banyak nilai karena menghemat pelaksana dari menulis beberapa logika umum.interface
atau tidak hanya relevan dalam C # yang melarang pewarisan berganda penuh.Seluruh konsep antarmuka dibuat untuk mendukung keluarga kelas yang memiliki API bersama.
Ini secara eksplisit mengatakan bahwa setiap penggunaan antarmuka menyiratkan bahwa ada (atau diharapkan) lebih dari satu implementasi spesifikasinya.
Kerangka kerja DI telah memperkeruh perairan di sini karena banyak dari mereka memerlukan antarmuka meskipun hanya akan ada satu implementasi - bagi saya ini adalah overhead yang tidak masuk akal karena dalam banyak kasus hanya cara yang lebih kompleks dan lebih lambat untuk memanggil yang baru, tetapi adalah apa adanya.
Jawabannya ada pada pertanyaan itu sendiri. Jika Anda memiliki kelas abstrak, Anda sedang mempersiapkan pembuatan lebih dari satu kelas turunan dengan API umum. Dengan demikian, penggunaan antarmuka ditunjukkan dengan jelas.
sumber
find ... -exec perl -pi -e ...
dan mungkin memperbaiki kesalahan kompilasi sepele. Maksudinterface
sebagai kode (Anda berbicara tentang C # -interface
s, bukan antarmuka abstrak, seperti seperangkat kelas / fungsi / dll), dan mengakhirinya "... tetapi masih melarang beberapa penuh warisan." Tidak perlu untukinterface
jika Anda memiliki MI.Jika kita ingin menjawab pertanyaan secara eksplisit, penulis mengatakan, "Apakah masuk akal untuk mendefinisikan antarmuka ini jika saya sudah memiliki kelas abstrak TypeNameMapper atau kelas abstrak sudah cukup?"
Jawabannya adalah ya dan tidak - Ya, Anda harus membuat antarmuka meskipun Anda sudah memiliki kelas dasar abstrak (karena Anda tidak boleh merujuk ke kelas dasar abstrak dalam kode klien apa pun), dan tidak, karena Anda seharusnya tidak membuat kelas dasar abstrak tanpa adanya antarmuka.
Jelas bahwa Anda belum cukup memikirkan API yang ingin Anda bangun. Munculkan API terlebih dahulu, lalu berikan implementasi parsial jika diinginkan. Fakta bahwa kelas dasar abstrak Anda mengetik kode memeriksa sudah cukup untuk memberi tahu Anda itu bukan abstraksi yang tepat.
Seperti pada kebanyakan hal dalam OOD, ketika Anda berada di alur dan memiliki model objek Anda dilakukan dengan baik, kode Anda akan memberi tahu Anda tentang apa yang terjadi selanjutnya. Mulailah dengan sebuah antarmuka, terapkan antarmuka itu di kelas yang Anda butuhkan. Jika Anda menemukan diri Anda menulis kode yang serupa, ekstrak menjadi kelas dasar abstrak - itu antarmuka yang penting, kelas dasar abstrak hanyalah pembantu dan mungkin ada lebih dari satu.
sumber
Ini cukup sulit dijawab tanpa mengetahui sisa aplikasi.
Dengan asumsi Anda menggunakan beberapa jenis model DI dan telah merancang kode Anda agar dapat diperluas sebisa mungkin (sehingga Anda dapat menambahkan
TypeNameMapper
dengan mudah) saya akan mengatakan ya.Alasan untuk:
interface
Anda tidak perlu khawatir tentang hal itu dalam implementasi anakinterface
s. Sementara banyak dari mereka yang bekerja dengan kelas abstrak itu tidak selalu diberikan dan saya sangat percaya dalam mengikuti jalan yang sama dengan 99% pengguna perpustakaan lainnya jika memungkinkan.Alasan menentang:
class
/interface
perubahan ada sedikit overhead tambahanSemua hal dipertimbangkan saya akan mengatakan bahwa Anda harus membuat
interface
. Alasannya cukup dapat diabaikan tetapi, sementara mungkin untuk menggunakan abstrak dalam mengejek dan IoC sering jauh lebih mudah dengan antarmuka. Namun pada akhirnya, saya tidak akan mengkritik kode rekan jika mereka sebaliknya.sumber