Pertimbangkan sebuah antarmuka:
interface IWaveGenerator
{
SoundWave GenerateWave(double frequency, double lengthInSeconds);
}
Antarmuka ini diimplementasikan oleh sejumlah kelas yang menghasilkan gelombang dengan bentuk yang berbeda (misalnya, SineWaveGenerator
dan SquareWaveGenerator
).
Saya ingin menerapkan kelas yang menghasilkan SoundWave
berdasarkan pada data musik, bukan data suara mentah. Itu akan menerima nama catatan dan panjang dalam hal ketukan (bukan detik), dan secara internal menggunakan IWaveGenerator
fungsi untuk membuat yang SoundWave
sesuai.
Pertanyaannya adalah, haruskah NoteGenerator
mengandung IWaveGenerator
atau mewarisi dari IWaveGenerator
implementasi?
Saya condong ke arah komposisi karena dua alasan:
1- Ini memungkinkan saya untuk menyuntikkan apapun IWaveGenerator
ke NoteGenerator
dinamis. Juga, saya hanya perlu satu NoteGenerator
kelas, bukan SineNoteGenerator
, SquareNoteGenerator
, dll
2- Tidak perlu untuk NoteGenerator
mengekspos antarmuka tingkat bawah yang ditentukan oleh IWaveGenerator
.
Namun saya memposting pertanyaan ini untuk mendengar pendapat lain tentang ini, mungkin poin yang belum saya pikirkan.
BTW: Saya akan mengatakan NoteGenerator
secara konseptual IWaveGenerator
karena menghasilkan SoundWave
s.
Apakah NoteGenerator "konseptual" atau tidak, IWaveGenerator tidak masalah.
Anda hanya boleh mewarisi dari antarmuka jika Anda berencana untuk mengimplementasikan antarmuka yang tepat sesuai dengan Prinsip Pergantian Liskov, yaitu dengan semantik yang benar serta sintaks yang benar.
Kedengarannya seperti NoteGenerator Anda mungkin memiliki antarmuka yang sama secara sintaksis, tetapi semantiknya (dalam hal ini, arti dari parameter yang diperlukan) akan sangat berbeda, jadi menggunakan pewarisan dalam kasus ini akan sangat menyesatkan dan berpotensi rawan kesalahan. Anda berhak memilih komposisi di sini.
sumber
NoteGenerator
akan mengimplementasikanGenerateWave
tetapi menafsirkan parameter secara berbeda, ya saya setuju itu akan menjadi ide yang mengerikan. Maksud saya NoteGenerator adalah jenis spesialisasi generator gelombang: ia dapat menerima data input 'tingkat lebih tinggi' alih-alih hanya data suara mentah (mis. Nama catatan alih-alih frekuensi). YaitusineWaveGenerator.generate(440) == noteGenerator.generate("a4")
. Maka datanglah pertanyaan, komposisi atau warisan.Kedengarannya seperti
NoteGenerator
bukanWaveGenerator
, jadi karena itu seharusnya tidak mengimplementasikan antarmuka.Komposisi adalah pilihan yang tepat.
sumber
NoteGenerator
secara konseptualIWaveGenerator
karena menghasilkanSoundWave
s.GenerateWave
, maka itu bukanIWaveGenerator
. Tapi sepertinya menggunakan IWaveGenerator (mungkin lebih?), Maka komposisi.GenerateWave
fungsi seperti yang tertulis dalam pertanyaan. Tapi dari komentar di atas saya kira bukan itu yang sebenarnya ada dalam pikiran OP.Anda memiliki wadah solid untuk komposisi. Anda mungkin memiliki kasus untuk juga menambahkan warisan. Cara mengetahuinya adalah dengan melihat kode panggilan. Jika Anda ingin dapat menggunakan
NoteGenerator
kode panggilan yang ada yang mengharapkanIWaveGenerator
, maka Anda perlu mengimplementasikan antarmuka. Anda sedang mencari kebutuhan akan substitusi. Apakah secara konseptual generator gelombang "is-a" ada di samping itu.sumber
IHasWaveGenerator
, dan metode yang relevan pada antarmuka itu adalahGetWaveGenerator
yang mengembalikan instanceIWaveGenerator
. Tentu saja penamaan bisa diubah. (Saya hanya berusaha menyempurnakan detail - beri tahu saya jika detail saya salah.)Tidak masalah untuk
NoteGenerator
mengimplementasikan antarmuka, dan juga, untukNoteGenerator
memiliki implementasi internal yang merujuk (dengan komposisi) yang lainIWaveGenerator
.Secara umum, komposisi menghasilkan kode yang lebih mudah dikelola (yaitu dapat dibaca), karena Anda tidak memiliki kerumitan penggantian alasan. Pengamatan Anda tentang matriks kelas yang Anda miliki ketika menggunakan warisan juga tepat, dan mungkin dapat dianggap sebagai bau kode yang menunjuk ke arah komposisi.
Warisan lebih baik digunakan ketika Anda memiliki implementasi yang ingin Anda mengkhususkan atau sesuaikan, yang tampaknya tidak menjadi masalah di sini: Anda hanya perlu menggunakan antarmuka.
sumber
NoteGenerator
diterapkanIWaveGenerator
karena karena catatan memerlukan ketukan. bukan detik-.NoteGenerator
secara konseptual sebuahIWaveGenerator
karena ia menghasilkanSoundWave
s", dan, ia sedang mempertimbangkan warisan, jadi saya mengambil kebebasan mental untuk kemungkinan bahwa mungkin ada beberapa implementasi antarmuka, meskipun ada lagi antarmuka atau tanda tangan yang lebih baik untuk kelas.