Artikel ini menggambarkan konsep pewarisan dan gubahan di Jawa. Contoh pertama menunjukkan warisan dan kemudian menunjukkan cara memperbaik reka bentuk warisan menggunakan gubahan. Kami akan meringkaskan cara memilih antara mereka pada akhirnya.
1. Warisan
Katakan kita mempunyai kelasInsect
(serangga Inggeris) Kelas ini mengandungi dua kaedah: 1. move()
(dari bahasa Inggeris bergerak) dan 2. attack()
(dari serangan Inggeris)
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 menentukan kelas Bee
(lebah Inggeris), yang merupakan salah satu jenis Insect
, tetapi mempunyai pelaksanaan yang berbeza attack()
dan move()
. Ini boleh dilakukan 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();
}
}
Gambar rajah hierarki kelas agak mudah: Hasil pelaksanaan:
Fly
Fly
Attack
"Fly" ditaip dua kali, jadi kaedah move()
dipanggil dua kali. Tetapi ia hanya perlu dipanggil sekali. Masalahnya disebabkan oleh super.attack()
. Kaedah ini attack ()
memanggil kaedah move()
kelas Insect
. Apabila subkelas memanggil super.attack ()
, ia juga memanggil kaedah yang diganti move()
. Untuk menyelesaikan masalah kita boleh:
- Hapuskan
attack()
kaedah subkelas. Ini akan menjadikan subkelas bergantung padaattack()
pelaksanaan kaedah superclass. Jikaattack()attack()
superclass mula menggunakan kaedah yang berbeza untuk bergerak, subclass perlu berubah juga. Ini adalah enkapsulasi yang buruk. -
Tulis semula kaedah
attack()
seperti berikut:public void attack() { move(); System.out.println("Attack"); }
-
Ini menjamin hasil yang betul kerana subkelas tidak lagi bergantung pada superclass. Walau bagaimanapun, kod itu adalah pendua superclass. (kaedah
attack()
melakukan perkara yang lebih kompleks daripada hanya mengeluarkan rentetan). Ini bukan reka bentuk perisian yang baik dan tidak sepatutnya ada kod pendua.
2. Komposisi
Anda boleh menggunakan komposisi dan bukannya warisan. Mari lihat penyelesaian menggunakannya. Fungsi iniattack()
diabstraksikan sebagai antara muka.
interface Attack {
public void move();
public void attack();
}
Jenis serangan yang berbeza boleh ditakrifkan dengan melaksanakan antara muka 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);
}
}
Oleh kerana fungsi serangan adalah luaran, kelas Insect
tidak lagi mengandunginya.
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;
}
}
Kelas Bee
(dari English Bee), bagaimana jenis Insect
boleh 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();
}
}
Gambar rajah 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();
}
}
Keputusan pelaksanaan:
fly
move
fly
sting
3. Bila hendak menggunakan pendekatan ini?
2 perkara berikut boleh membantu anda memutuskan antara warisan dan gubahan:- Jika anda berurusan dengan hubungan antara kelas dalam bentuk "IS" dan kelas ingin menyediakan semua antara mukanya kepada kelas lain, maka warisan adalah lebih baik.
- jika perhubungan adalah "HAS", maka komposisi diutamakan.
- Bloch, Joshua. java berkesan. Pearson Education 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