Ushbu maqola Java-da meros va kompozitsiya tushunchalarini tasvirlaydi. Birinchi misol merosni ko'rsatadi va keyin kompozitsiyadan foydalangan holda meros dizaynini qanday yaxshilashni ko'rsatadi. Oxirida ular orasidan qanday tanlashni umumlashtiramiz.
1. Meros
Faraz qilaylik, bizda sinf mavjudInsect
(ingliz hasharotlari) Bu sinf ikkita usulni o'z ichiga oladi: 1. move()
(inglizcha move dan) va 2. attack()
(inglizcha hujumdan)
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");
}
}
Endi siz klassni (inglizcha ari) aniqlamoqchisiz Bee
, u turlardan biri bo'lib Insect
, lekin attack()
va ning turli xil ilovalariga ega move()
. Buni meros yordamida amalga oshirish mumkin:
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();
}
}
Sinf ierarxiyasi diagrammasi juda oddiy: Bajarish natijasi:
Fly
Fly
Attack
"Fly" ikki marta yoziladi, shuning uchun usul move()
ikki marta chaqiriladi. Lekin u faqat bir marta chaqirilishi kerak. Muammo sabab bo'ladi super.attack()
. Usul sinf usulini attack ()
chaqiradi . Subklass qo'ng'iroq qilganda , u ham bekor qilingan usulni chaqiradi . Muammoni hal qilish uchun biz: move()
Insect
super.attack ()
move()
- Subklass usulini yo'q qiling
attack()
. Bu kichik sinfni supersinf usulini amalga oshirishga bog'liq qiladiattack()
. Agarattack()attack()
supersinf harakatlanish uchun boshqa usuldan foydalana boshlasa, pastki sinf ham o'zgarishi kerak bo'ladi. Bu yomon inkapsulyatsiya. -
Usulni
attack()
quyidagicha qayta yozing:public void attack() { move(); System.out.println("Attack"); }
-
Bu to'g'ri natijani kafolatlaydi, chunki pastki sinf endi yuqori sinfga bog'liq emas. Biroq, kod superklassning dublikatidir. (usul
attack()
faqat satrni chiqarishdan ko'ra murakkabroq ishlarni bajaradi). Bu yaxshi dasturiy ta'minot dizayni emas va ikki nusxadagi kod bo'lmasligi kerak.
2. Tarkibi
Meros o'rniga kompozitsiyadan foydalanishingiz mumkin. Keling, uni ishlatadigan yechimni ko'rib chiqaylik. Funktsiyaattack()
interfeys sifatida abstrakt qilingan.
interface Attack {
public void move();
public void attack();
}
Hujum interfeysini amalga oshirish orqali har xil turdagi hujumlarni aniqlash mumkin.
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);
}
}
Hujum funktsiyasi tashqi bo'lgani uchun sinf Insect
endi uni o'z ichiga olmaydi.
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;
}
}
Sinf Bee
(inglizcha Bee dan), turi qanday Insect
hujum qilishi mumkin.
// 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();
}
}
Sinf diagrammasi:
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();
}
}
Amalga oshirish natijasi:
fly
move
fly
sting
3. Ushbu yondashuvlardan qachon foydalanish kerak?
Quyidagi 2 nuqta meros va tarkib o'rtasida qaror qabul qilishingizga yordam beradi:- Agar siz "IS" shaklidagi sinflar o'rtasidagi munosabat bilan shug'ullanayotgan bo'lsangiz va sinf o'zining barcha interfeyslarini boshqa sinfga taqdim qilmoqchi bo'lsa, meros afzalroqdir.
- agar munosabatlar "HAS" bo'lsa, unda kompozitsiyaga ustunlik beriladi.
- Bloch, Joshua. Samarali java. Pearson Education Hindiston, 2008 yil
- 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