Artikel ini menggambarkan konsep pewarisan dan komposisi di Java. Contoh pertama mendemonstrasikan pewarisan dan kemudian menunjukkan cara meningkatkan desain pewarisan menggunakan komposisi. Kami akan merangkum cara memilih di antara keduanya di bagian akhir.
1. Warisan
Misalkan kita mempunyai sebuah kelasInsect
(bahasa Inggris serangga). Kelas ini berisi dua metode: 1. move()
(dari bahasa Inggris move) dan 2. attack()
(dari bahasa Inggris serangan)
class Insect {
private int size;
private String color;
public Insect(int size, String color) {
this.size = size;
this.color = color;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void move() {
System.out.println("Move");
}
public void attack() {
move(); //assuming an insect needs to move before attacking
System.out.println("Attack");
}
}
Sekarang Anda ingin mendefinisikan sebuah kelas Bee
(Bahasa Inggris bee), yang merupakan salah satu tipe Insect
, tetapi memiliki implementasi attack()
dan move()
. Ini dapat dilakukan dengan menggunakan warisan:
class Bee extends Insect {
public Bee(int size, String color) {
super(size, color);
}
public void move() {
System.out.println("Fly");
}
public void attack() {
move();
super.attack();
}
}
public class InheritanceVSComposition {
public static void main(String[] args) {
Insect i = new Bee(1, "red");
i.attack();
}
}
Diagram hierarki kelas cukup sederhana: Hasil eksekusi:
Fly
Fly
Attack
"Fly" diketik dua kali, sehingga metode ini move()
dipanggil dua kali. Tapi itu hanya boleh dipanggil sekali. Masalah tersebut disebabkan oleh super.attack()
. Metode ini attack ()
memanggil metode move()
kelas Insect
. Ketika subkelas memanggil super.attack ()
, ia juga memanggil metode yang diganti move()
. Untuk memperbaiki masalah ini kita dapat:
- Hilangkan
attack()
metode subkelas. Hal ini akan membuat subkelas bergantung padaattack()
implementasi metode superkelas. Jikaattack()attack()
superkelas mulai menggunakan metode perpindahan yang berbeda, subkelas juga perlu diubah. Ini adalah enkapsulasi yang buruk. -
Tulis ulang metodenya
attack()
sebagai berikut:public void attack() { move(); System.out.println("Attack"); }
-
Hal ini menjamin hasil yang benar karena subkelas tidak lagi bergantung pada superkelas. Namun, kode tersebut merupakan duplikat dari superclass. (metode ini
attack()
melakukan hal-hal yang lebih kompleks daripada sekadar mengeluarkan string). Ini bukan desain perangkat lunak yang bagus dan tidak boleh ada kode duplikat.
2. Komposisi
Anda dapat menggunakan komposisi alih-alih warisan. Mari kita lihat solusi menggunakannya. Fungsi iniattack()
diabstraksi sebagai antarmuka.
interface Attack {
public void move();
public void attack();
}
Berbagai jenis serangan dapat ditentukan dengan mengimplementasikan antarmuka Serangan.
class AttackImpl implements Attack {
private String move;
private String attack;
public AttackImpl(String move, String attack) {
this.move = move;
this.attack = attack;
}
@Override
public void move() {
System.out.println(move);
}
@Override
public void attack() {
move();
System.out.println(attack);
}
}
Karena fungsi serangan bersifat eksternal, kelas Insect
tidak lagi memuatnya.
class Insect {
private int size;
private String color;
public Insect(int size, String color) {
this.size = size;
this.color = color;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
Class Bee
(dari bahasa Inggris Bee), bagaimana tipenya Insect
dapat menyerang.
// This wrapper class wrap an Attack object
class Bee extends Insect implements Attack {
private Attack attack;
public Bee(int size, String color, Attack attack) {
super(size, color);
this.attack = attack;
}
public void move() {
attack.move();
}
public void attack() {
attack.attack();
}
}
Diagram kelas:
public class InheritanceVSComposition2 {
public static void main(String[] args) {
Bee a = new Bee(1, "black", new AttackImpl("fly", "move"));
a.attack();
// if you need another implementation of move()
// there is no need to change Insect, we can quickly use new method to attack
Bee b = new Bee(1, "black", new AttackImpl("fly", "sting"));
b.attack();
}
}
Hasil eksekusi:
fly
move
fly
sting
3. Kapan pendekatan ini digunakan?
2 poin berikut dapat membantu Anda memutuskan antara warisan dan komposisi:- Jika Anda berurusan dengan hubungan antar kelas dalam bentuk "IS" dan suatu kelas ingin menyediakan semua antarmukanya ke kelas lain, maka pewarisan lebih disukai.
- jika hubungannya "HAS", maka komposisi lebih diutamakan.
- Bloch, Joshua. Java yang efektif. Pearson Pendidikan India, 2008
- https://stackoverflow.com/questions/49002/prefer-composition-over-inheritance
- https://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition--which-one-should...
GO TO FULL VERSION