Warisan Berganda di Jawa
Warisan berganda adalah kemampuan untuk membuat kelas dengan beberapa kelas induk. Tidak seperti bahasa berorientasi objek populer lainnya seperti C++, Java tidak mendukung pewarisan banyak kelas. Dia tidak mendukungnya karena kemungkinan menghadapi “masalah berlian” dan sebaliknya lebih memilih untuk memberikan semacam pendekatan komprehensif untuk menyelesaikannya, menggunakan opsi terbaik agar kita dapat mencapai hasil warisan yang serupa."Masalah Berlian"
Untuk memahami masalah berlian dengan lebih sederhana, mari kita asumsikan bahwa warisan berganda didukung di Java. Dalam hal ini, kita bisa mendapatkan kelas dengan hierarki yang ditunjukkan pada gambar di bawah. Mari kita asumsikan ituSuperClass
adalah kelas abstrak yang menggambarkan metode tertentu, dan kelas-kelas
ClassA
tersebut
ClassB
merupakan kelas nyata.
SuperClass.java
package com.journaldev.inheritance;
public abstract class SuperClass {
public abstract void doSomething();
}
ClassA.java
package com.journaldev.inheritance;
public class ClassA extends SuperClass{
@Override
public void doSomething(){
System.out.println("Какая-то реализация класса A");
}
//собственный метод класса ClassA
public void methodA(){
}
}
Sekarang, mari kita asumsikan bahwa kelas tersebut
ClassC
mewarisi dari
ClassA
dan
ClassB
pada saat yang sama, dan pada saat yang sama memiliki implementasi berikut:
package com.journaldev.inheritance;
public class ClassC extends ClassA, ClassB{
public void test(){
//вызов метода родительского класса
doSomething();
}
}
Perhatikan bahwa metode tersebut
test()
memanggil metode
doSomething()
kelas induk, yang akan menimbulkan ambiguitas karena kompiler tidak mengetahui metode superkelas mana yang harus dipanggil. Karena bentuk diagram pewarisan kelas pada situasi ini yang menyerupai garis bentuk berlian segi, maka permasalahan tersebut disebut “Masalah Berlian”. Inilah alasan utama mengapa Java tidak mendukung pewarisan banyak kelas. Perhatikan bahwa masalah pewarisan beberapa kelas ini juga dapat terjadi pada tiga kelas yang memiliki setidaknya satu metode umum.
Warisan berganda dan antarmuka
Anda mungkin telah memperhatikan bahwa saya selalu mengatakan "warisan berganda tidak didukung antar kelas", tetapi ini didukung antar antarmuka. Contoh sederhana ditunjukkan di bawah ini:InterfaceA.java
package com.journaldev.inheritance;
public interface InterfaceA {
public void doSomething();
}
InterfaceB.java
package com.journaldev.inheritance;
public interface InterfaceB {
public void doSomething();
}
Perhatikan bahwa kedua antarmuka memiliki metode dengan nama yang sama. Sekarang katakanlah kita memiliki antarmuka yang mewarisi kedua antarmuka.
InterfaceC.java
package com.journaldev.inheritance;
public interface InterfaceC extends InterfaceA, InterfaceB {
//метод, с тем же названием описан в InterfaceA и InterfaceB
public void doSomething();
Di sini, semuanya ideal, karena antarmuka hanyalah reservasi/deskripsi suatu metode, dan implementasi metode itu sendiri akan berada di kelas konkret yang mengimplementasikan antarmuka ini, sehingga tidak ada kemungkinan menghadapi ambiguitas dengan pewarisan berganda antarmuka. Inilah sebabnya mengapa kelas-kelas di Java dapat mewarisi dari banyak antarmuka. Mari kita tunjukkan dengan contoh di bawah ini.
InterfacesImpl.java
package com.journaldev.inheritance;
public class InterfacesImpl implements InterfaceA, InterfaceB, InterfaceC {
@Override
public void doSomething() {
System.out.println("doSomething реализация реального класса ");
}
public static void main(String[] args) {
InterfaceA objA = new InterfacesImpl();
InterfaceB objB = new InterfacesImpl();
InterfaceC objC = new InterfacesImpl();
//все вызываемые ниже методы получат одинаковую реализацию конкретного класса
objA.doSomething();
objB.doSomething();
objC.doSomething();
}
}
Anda mungkin telah memperhatikan bahwa setiap kali saya mengganti metode yang dijelaskan dalam superclass atau antarmuka, saya menggunakan anotasi @Override. Ini adalah salah satu dari tiga anotasi Java bawaan dan Anda harus selalu menggunakannya saat mengganti metode.
Komposisi sebagai penyelamat
Lalu bagaimana jika kita ingin menggunakanmethodA()
kelas
ClassA
dan fungsi
methodB()
kelas
ClassB
di
ClassС
? Solusi untuk hal ini bisa berupa komposisi - versi yang ditulis ulang
ClassC
yang mengimplementasikan kedua metode kelas
ClassA
dan
ClassB
juga memiliki implementasi
doSomething()
untuk salah satu objek.
ClassC.java
package com.journaldev.inheritance;
public class ClassC{
ClassA objA = new ClassA();
ClassB objB = new ClassB();
public void test(){
objA.doSomething();
}
public void methodA(){
objA.methodA();
}
public void methodB(){
objB.methodB();
}
}
Komposisi atau warisan?
Merupakan praktik pemrograman Java yang baik untuk memanfaatkan komposisi dibandingkan pewarisan. Kami akan melihat beberapa aspek yang mendukung pendekatan ini.-
Misalkan kita mempunyai kombinasi kelas induk-pewaris berikut ini:
ClassC.java
package com.journaldev.inheritance; public class ClassC{ public void methodC(){ } }
ClassD.java
package com.journaldev.inheritance; public class ClassD extends ClassC{ public int test(){ return 0; } }
Kode di atas dikompilasi dan berfungsi dengan baik, tetapi bagaimana jika
ClassC
diterapkan secara berbeda:package com.journaldev.inheritance; public class ClassC{ public void methodC(){ } public void test(){ } }
Perhatikan bahwa metode ini
test()
sudah ada di kelas turunan, tetapi mengembalikan hasil dengan tipe berbeda. SekarangClassD
, jika Anda menggunakan IDE, itu tidak akan dapat dikompilasi. Anda akan disarankan untuk mengubah tipe pengembalian di kelas turunan atau super.Sekarang mari kita bayangkan situasi di mana ada pewarisan kelas multi-level dan superkelas tidak tersedia untuk perubahan kita. Sekarang, untuk menghilangkan kesalahan kompilasi, kami tidak memiliki pilihan lain selain mengubah tanda tangan atau nama metode subkelas. Kami juga harus melakukan perubahan di semua tempat di mana metode ini dipanggil. Jadi, warisan membuat kode kita rapuh.
Masalah yang dijelaskan di atas tidak pernah terjadi dalam kasus komposisi, dan oleh karena itu membuat komposisi lebih disukai daripada warisan.
-
Masalah selanjutnya dengan pewarisan adalah kita mengekspos semua metode induk kepada klien. Dan jika superclass tidak dirancang dengan benar dan mengandung celah keamanan. Kemudian, meskipun kita menjaga keamanan sepenuhnya dalam implementasi subkelas kita, kita masih akan bergantung pada implementasi kelas induk yang cacat.
Komposisi membantu kita dalam menyediakan akses terkontrol ke metode superclass, sedangkan warisan tidak mempertahankan kontrol apa pun atas metodenya. Ini juga merupakan salah satu keunggulan utama komposisi dibandingkan warisan.
-
Manfaat lain dari komposisi adalah menambah fleksibilitas saat memanggil metode. Implementasi kelas
ClassC
yang dijelaskan di atas tidak optimal dan menggunakan pengikatan awal ke metode yang dipanggil. Perubahan minimal akan memungkinkan kita membuat pemanggilan metode menjadi fleksibel dan memungkinkan pengikatan yang terlambat (pengikatan saat runtime).ClassC.java
package com.journaldev.inheritance; public class ClassC{ SuperClass obj = null; public ClassC(SuperClass o){ this.obj = o; } public void test(){ obj.doSomething(); } public static void main(String args[]){ ClassC obj1 = new ClassC(new ClassA()); ClassC obj2 = new ClassC(new ClassB()); obj1.test(); obj2.test(); } }
Program di atas akan menampilkan:
doSomething implementation of A doSomething implementation of B
Fleksibilitas dalam pemanggilan metode ini tidak terlihat pada pewarisan, sehingga komposisi merupakan pendekatan terbaik.
-
Pengujian unit lebih mudah dalam hal komposisi karena kita tahu bahwa untuk semua metode yang digunakan di superkelas kita dapat menghentikan pengujian, sedangkan dalam pewarisan kita sangat bergantung pada superkelas dan tidak tahu bagaimana metode kelas induk. akan digunakan. Jadi, karena pewarisan, kita harus menguji semua metode superclass, yang merupakan pekerjaan yang tidak perlu.
Idealnya, pewarisan hanya boleh digunakan ketika hubungan “ is-a ” berlaku untuk kelas induk dan anak, jika tidak, komposisi harus diutamakan.
GO TO FULL VERSION