Dalam upaya untuk sepenuhnya memahami bagaimana menyelesaikan beberapa masalah warisan Java, saya memiliki pertanyaan klasik yang perlu saya klarifikasi.
Katakanlah saya memiliki kelas Animal
ini memiliki sub kelas Bird
dan Horse
dan saya perlu membuat kelas Pegasus
yang memanjang dari Bird
dan Horse
karena Pegasus
merupakan burung dan kuda.
Saya pikir ini adalah masalah berlian klasik. Dari apa yang saya bisa mengerti cara klasik untuk menyelesaikan ini adalah dengan membuat Animal
, Bird
dan Horse
kelas antarmuka dan mengimplementasikannya Pegasus
.
Saya bertanya-tanya apakah ada cara lain untuk memecahkan masalah di mana saya masih bisa membuat objek untuk burung dan kuda. Jika ada cara untuk bisa menciptakan hewan juga itu akan bagus tapi tidak perlu.
public class Pegasus extends Horse implements Flying
.Jawaban:
Anda dapat membuat antarmuka untuk kelas hewan (kelas dalam arti biologis), seperti
public interface Equidae
untuk kuda danpublic interface Avialae
burung (saya bukan ahli biologi, jadi istilahnya mungkin salah).Maka Anda masih dapat membuat
dan
dan juga
Menambahkan dari komentar:
Untuk mengurangi kode duplikat, Anda bisa membuat kelas abstrak yang berisi sebagian besar kode umum hewan yang ingin Anda terapkan.
Memperbarui
Saya ingin menambahkan satu detail lagi. Seperti yang Brian katakan , ini adalah sesuatu yang sudah diketahui OP.
Namun, saya ingin menekankan, bahwa saya menyarankan untuk memotong masalah "multi-inheritance" dengan antarmuka dan bahwa saya tidak merekomendasikan untuk menggunakan antarmuka yang sudah mewakili tipe konkret (seperti Bird) tetapi lebih merupakan perilaku (yang lain merujuk pada mengetik bebek, itu bagus juga, tapi maksud saya adil: kelas biologis burung, Avialae). Saya juga tidak menyarankan untuk menggunakan nama antarmuka yang dimulai dengan huruf 'I', seperti
IBird
, yang tidak memberi tahu apa-apa tentang mengapa Anda memerlukan antarmuka. Itulah perbedaan dari pertanyaan: membangun hierarki warisan menggunakan antarmuka, menggunakan kelas abstrak saat berguna, mengimplementasikan kelas konkret di mana diperlukan dan menggunakan delegasi jika sesuai.sumber
AbstractHorse
, yang juga dapat digunakan untuk membangun Zebra atau binatang seperti kuda lainnya.AbstractEquidae
akan lebih cocok daripadaAbstractHorse
. Akan aneh untuk memiliki zebra memperpanjang kuda abstrak. Jawaban yang bagus.Duck
implementasi kelasAvialae
?Ada dua pendekatan mendasar untuk menggabungkan objek:
Cara kerjanya adalah Anda memiliki objek Hewan. Di dalam objek itu Anda kemudian menambahkan objek lebih lanjut yang memberikan properti dan perilaku yang Anda butuhkan.
Sebagai contoh:
Sekarang
IFlier
hanya terlihat seperti ini:Jadi
Bird
terlihat seperti ini:Sekarang Anda memiliki semua keunggulan Warisan. Anda dapat menggunakan kembali kode. Anda dapat memiliki koleksi IFliers, dan dapat menggunakan semua keuntungan lain dari polimorfisme, dll.
Namun Anda juga memiliki semua fleksibilitas dari Komposisi. Anda dapat menerapkan sebanyak mungkin antarmuka dan kelas dukungan komposit yang berbeda sesuai keinginan untuk setiap jenis
Animal
- dengan sebanyak mungkin kendali yang Anda perlukan atas cara setiap bit diatur.Strategi Pendekatan alternatif pola komposisi
Pendekatan alternatif tergantung pada apa dan bagaimana Anda lakukan adalah membuat
Animal
kelas dasar berisi koleksi internal untuk menyimpan daftar perilaku yang berbeda. Dalam hal ini Anda akhirnya menggunakan sesuatu yang lebih dekat dengan Pola Strategi. Itu memang memberi keuntungan dalam hal menyederhanakan kode (misalnyaHorse
tidak perlu tahu apa-apa tentangQuadruped
atauHerbivore
) tetapi jika Anda tidak juga melakukan pendekatan antarmuka Anda kehilangan banyak keuntungan polimorfisme, dll.sumber
getFlier()
harus diterapkan kembali untuk setiap jenis burung.MathsTeacher
danEnglishTeacher
kedua mewarisiTeacher
,ChemicalEngineer
,MaterialsEngineer
dll mewarisiEngineer
.Teacher
danEngineer
keduanya mengimplementasikanComponent
. ThePerson
kemudian hanya memiliki daftarComponent
s, dan Anda dapat memberikan mereka hakComponent
s untuk ituPerson
. yaituperson.getComponent(Teacher.class)
,,person.getComponent(MathsTeacher.class)
dll.Saya punya ide bodoh:
sumber
Bolehkah saya menyarankan konsep Duck-typing ?
Kemungkinan besar Anda cenderung membuat Pegasus memperluas antarmuka Burung dan Kuda, tetapi mengetik bebek sebenarnya menunjukkan bahwa Anda sebaiknya mewarisi perilaku . Seperti yang sudah dinyatakan dalam komentar, pegasus bukan burung tetapi bisa terbang. Jadi Pegasus Anda sebaiknya mewarisi
Flyable
-interface dan katakanlahGallopable
-interface.Konsep semacam ini digunakan dalam Pola Strategi . Contoh yang diberikan sebenarnya menunjukkan kepada Anda bagaimana seekor bebek mewarisi
FlyBehaviour
danQuackBehaviour
dan masih ada bebek, misalnyaRubberDuck
, yang tidak bisa terbang. Mereka bisa saja membuatDuck
perpanjanganBird
kelas-tetapi kemudian mereka akan memberikan beberapa fleksibilitas, karena setiap orangDuck
bisa terbang, bahkan orang miskinRubberDuck
.sumber
Secara teknis, Anda hanya dapat memperluas satu kelas pada satu waktu dan mengimplementasikan beberapa antarmuka, tetapi ketika meletakkan tangan pada rekayasa perangkat lunak, saya lebih suka menyarankan solusi khusus masalah yang umumnya tidak dapat dijawab. Ngomong-ngomong, itu adalah praktik OO yang baik, bukan untuk memperluas kelas konkret / hanya memperluas kelas abstrak untuk mencegah perilaku pewarisan yang tidak diinginkan - tidak ada yang namanya "hewan" dan tidak ada penggunaan objek hewan tetapi hanya hewan beton.
sumber
Di Java 8, yang masih dalam tahap pengembangan per Februari 2014, Anda bisa menggunakan metode default untuk mencapai semacam C ++ - seperti multiple inheritance. Anda juga bisa melihat tutorial ini yang menunjukkan beberapa contoh yang seharusnya lebih mudah untuk mulai bekerja daripada dokumentasi resmi.
sumber
Aman menyimpan kuda di kandang kuda dengan setengah pintu, karena kuda tidak bisa melewati setengah pintu. Karena itu saya menyiapkan layanan perumahan kuda yang menerima segala jenis kuda jenis dan meletakkannya di kandang dengan setengah pintu.
Jadi, apakah seekor kuda seperti binatang yang dapat terbang, bahkan seekor kuda?
Saya dulu sering berpikir tentang multiple inheritance, namun sekarang saya telah memprogram lebih dari 15 tahun, saya tidak lagi peduli untuk mengimplementasikan multiple inheritance.
Lebih sering daripada tidak, ketika saya telah mencoba untuk mengatasi suatu desain yang mengarah ke multiple inheritance, saya kemudian datang untuk merilis bahwa saya telah kehilangan memahami domain masalah.
ATAU
sumber
Java tidak memiliki masalah multiple inheritance, karena tidak memiliki multiple inheritance. Ini adalah desain, untuk menyelesaikan masalah pewarisan berganda nyata (Masalah berlian).
Ada berbagai strategi untuk mengurangi masalah. Yang paling mudah dicapai adalah objek Komposit yang disarankan Pavel (intinya bagaimana C ++ menanganinya). Saya tidak tahu apakah multiple inheritence via linierisasi C3 (atau serupa) ada di kartu untuk masa depan Java, tapi saya ragu.
Jika pertanyaan Anda bersifat akademis, maka solusi yang tepat adalah bahwa Burung dan Kuda lebih konkret, dan salah untuk berasumsi bahwa Pegasus hanyalah gabungan Burung dan Kuda. Akan lebih tepat untuk mengatakan bahwa Pegasus memiliki sifat intrinsik tertentu yang sama dengan Burung dan Kuda (yaitu mereka mungkin memiliki nenek moyang yang sama). Ini dapat dimodelkan secara memadai sebagai jawaban Moritz.
sumber
Saya pikir itu sangat tergantung pada kebutuhan Anda, dan bagaimana kelas hewan Anda digunakan dalam kode Anda.
Jika Anda ingin dapat menggunakan metode dan fitur implementasi Kuda dan Burung di dalam kelas Pegasus Anda, maka Anda bisa mengimplementasikan Pegasus sebagai komposisi Burung dan Kuda:
Kemungkinan lain adalah menggunakan Entity-Component-System alih-alih warisan untuk mendefinisikan hewan Anda. Tentu saja ini berarti, bahwa Anda tidak akan memiliki kelas individu hewan Jawa, tetapi mereka hanya ditentukan oleh komponen mereka.
Beberapa kode pseudo untuk pendekatan Entity-Component-System bisa terlihat seperti ini:
sumber
Anda dapat memiliki hierarki antarmuka dan kemudian memperluas kelas Anda dari antarmuka yang dipilih:
dan kemudian mendefinisikan kelas Anda sesuai kebutuhan, dengan memperluas antarmuka spesifik:
sumber
IBird
danIHorse
harus menerapkanIAnimal
bukannyaAnimal
Ehm, kelas Anda bisa menjadi subclass hanya untuk 1 lainnya, tetapi tetap saja, Anda dapat memiliki banyak antarmuka yang diimplementasikan, seperti yang Anda inginkan.
Pegasus sebenarnya adalah seekor kuda (ini adalah kasus khusus dari seekor kuda), yang mampu terbang (yang merupakan "keahlian" dari kuda istimewa ini). Dari sisi lain, Anda dapat mengatakan, Pegasus adalah seekor burung, yang dapat berjalan, dan bertingkat 4 - semuanya tergantung, bagaimana Anda lebih mudah menulis kode.
Seperti dalam kasus Anda, Anda dapat mengatakan:
sumber
Antarmuka tidak mensimulasikan banyak pewarisan. Pencipta Jawa menganggap pewarisan berganda salah, jadi tidak ada yang seperti itu di Jawa.
Jika Anda ingin menggabungkan fungsionalitas dua kelas menjadi komposisi objek sekali pakai. Yaitu
Dan jika Anda ingin mengekspos metode tertentu, tentukan mereka dan biarkan mereka mendelegasikan panggilan ke controller yang sesuai.
Di sini antarmuka mungkin berguna - jika
Component1
mengimplementasikan antarmukaInterface1
danComponent2
mengimplementasikanInterface2
, Anda dapat menentukanSehingga Anda bisa menggunakan objek secara bergantian di mana konteks memungkinkannya.
Jadi menurut saya, Anda tidak bisa masuk ke masalah berlian.
sumber
Seperti yang sudah Anda ketahui, beberapa pewarisan kelas di Java tidak mungkin, tetapi dimungkinkan dengan antarmuka. Anda mungkin juga ingin mempertimbangkan untuk menggunakan pola desain komposisi.
Saya menulis artikel yang sangat komprehensif tentang komposisi beberapa tahun yang lalu ...
/codereview/14542/multiple-inheritance-and-composition-with-java-and-c-updated
sumber
Lihat contoh di bawah ini untuk pemahaman yang lebih baik
Kapan Menggunakan Pola Penghias?
sumber
Untuk mengurangi kompleksitas dan menyederhanakan bahasa, multiple inheritance tidak didukung di java.
Pertimbangkan skenario di mana A, B dan C adalah tiga kelas. Kelas C mewarisi kelas A dan B. Jika kelas A dan B memiliki metode yang sama dan Anda memanggilnya dari objek kelas anak, akan ada ambiguitas untuk memanggil metode kelas A atau B.
Karena kesalahan waktu kompilasi lebih baik daripada kesalahan runtime, java membuat kesalahan waktu kompilasi jika Anda mewarisi 2 kelas. Jadi apakah Anda memiliki metode yang sama atau berbeda, akan ada kesalahan waktu kompilasi sekarang.
sumber
Untuk memecahkan masalah pewarisan mutiple di antarmuka Java → digunakan
Catatan J2EE (core JAVA) Oleh Tn. KVR Halaman 51
sumber