Meskipun ini adalah pertanyaan umum, ini juga khusus untuk masalah yang saya alami saat ini. Saat ini saya memiliki antarmuka yang ditentukan dalam solusi saya yang disebut
public interface IContextProvider
{
IDataContext { get; set; }
IAreaContext { get; set; }
}
Antarmuka ini sering digunakan di seluruh program dan karenanya saya memiliki akses mudah ke objek yang saya butuhkan. Namun pada tingkat yang cukup rendah dari bagian dari program saya, saya perlu akses ke kelas lain yang akan menggunakan IAreaContext dan melakukan beberapa operasi dari itu. Jadi saya telah membuat antarmuka pabrik lain untuk melakukan kreasi yang disebut:
public interface IEventContextFactory
{
IEventContext CreateEventContext(int eventId);
}
Saya memiliki kelas yang mengimplementasikan IContextProvider dan disuntikkan menggunakan NinJect. Masalah yang saya miliki adalah bahwa area di mana saya perlu menggunakan IEventContextFactory ini hanya memiliki akses ke IContextProvider dan menggunakan kelas lain yang membutuhkan antarmuka baru ini. Saya tidak ingin harus instantiate implementasi IEventContextFactory ini pada tingkat rendah dan lebih suka bekerja dengan antarmuka IEventContextFactory di seluruh. Namun saya juga tidak mau harus menyuntikkan parameter lain melalui konstruktor hanya untuk diteruskan ke kelas yang membutuhkannya yaitu
// example of problem
public class MyClass
{
public MyClass(IContextProvider context, IEventContextFactory event)
{
_context = context;
_event = event;
}
public void DoSomething()
{
// the only place _event is used in the class is to pass it through
var myClass = new MyChildClass(_event);
myClass.PerformCalculation();
}
}
Jadi pertanyaan utama saya adalah, apakah ini dapat diterima atau bahkan praktik umum atau baik untuk melakukan sesuatu seperti ini (antarmuka memperluas antarmuka lainnya):
public interface IContextProvider : IEventContextFactory
atau haruskah saya mempertimbangkan alternatif yang lebih baik untuk mencapai apa yang saya butuhkan. Jika saya belum memberikan informasi yang cukup untuk memberi saran, beri tahu saya dan saya dapat memberikan lebih banyak.
sumber
Jawaban:
Sementara antarmuka hanya menggambarkan perilaku tanpa implementasi apa pun, mereka masih dapat berpartisipasi dalam hierarki warisan. Sebagai contoh, bayangkan Anda memiliki, katakanlah, gagasan umum tentang a
Collection
. Antarmuka ini akan memberikan beberapa hal yang umum untuk semua koleksi, seperti metode untuk beralih ke anggota. Kemudian Anda dapat berpikir tentang beberapa koleksi objek yang lebih spesifik seperti aList
atau aSet
. Masing-masing mewarisi semua persyaratan perilakuCollection
, tetapi menambahkan persyaratan tambahan khusus untuk jenis koleksi tertentu.Setiap kali masuk akal untuk membuat hierarki warisan untuk antarmuka, maka Anda harus melakukannya. Jika dua antarmuka akan selalu ditemukan bersama, maka mereka mungkin harus digabung.
sumber
Ya, tetapi hanya jika itu masuk akal. Tanyakan kepada diri Anda pertanyaan-pertanyaan berikut dan jika satu atau lebih berlaku maka itu dapat diterima untuk mewarisi antarmuka dari yang lain.
Dalam contoh Anda, saya tidak berpikir itu menjawab ya untuk semua itu. Anda mungkin lebih baik menambahkannya sebagai properti lain:
sumber
IContextProvider
perluasanIEventContextFactory
, makaContextProvider
implementasinya juga perlu mengimplementasikan metode itu. Jika Anda menambahkannya sebagai properti, Anda mengatakan bahwa aContextProvider
memilikiIEventContextFactory
tetapi sebenarnya tidak tahu detail implementasi.Ya, boleh saja memperpanjang satu antarmuka dari yang lain.
Pertanyaan apakah itu hal yang benar untuk dilakukan dalam kasus tertentu tergantung pada apakah ada hubungan "is-a" yang sebenarnya di antara keduanya.
Apa yang diperlukan untuk hubungan "is-a" yang valid?
Pertama, harus ada perbedaan nyata antara kedua antarmuka, yaitu, harus ada contoh yang mengimplementasikan antarmuka induk tetapi bukan antarmuka anak. Jika tidak ada dan tidak akan ada contoh yang tidak mengimplementasikan kedua antarmuka, maka kedua antarmuka tersebut seharusnya digabungkan.
Kedua, itu harus menjadi kasus bahwa setiap instance dari antarmuka anak harus selalu merupakan instance dari orang tua: tidak ada logika (masuk akal) di mana Anda akan membuat instance dari antarmuka anak yang tidak akan masuk akal sebagai contoh dari antarmuka induk.
Jika keduanya benar, maka pewarisan adalah hubungan yang tepat untuk kedua antarmuka.
sumber
IReadOnlyList
dapat bermanfaat, bahkan jika semua kelas daftar saya menerapkanIList
(yang berasal dariIReadOnlyList
).Jika satu antarmuka selalu ingin meminta / menyediakan yang lain, maka silakan. Saya telah melihat ini dalam beberapa kasus dengan
IDisposible
yang masuk akal. Namun secara umum, Anda harus memastikan bahwa setidaknya satu antarmuka berperilaku lebih seperti sifat daripada tanggung jawab.Sebagai contoh, tidak jelas. Jika keduanya selalu bersama, cukup buat satu antarmuka. Jika yang satu selalu membutuhkan yang lain, saya akan khawatir tentang "X dan 1" jenis warisan yang sangat sering mengarah ke beberapa tanggung jawab, dan / atau masalah abstraksi bocor lainnya.
sumber