Бұл мақала Java тіліндегі мұра және композиция ұғымдарын суреттейді. Бірінші мысал мұраны көрсетеді, содан кейін құрам арқылы мұра дизайнын жақсарту жолын көрсетеді. Біз олардың арасында қалай таңдауға болатынын соңында қорытындылаймыз.
1. Мұрагерлік
Бізде сынып бар деп есептейікInsect
(ағылшынша жәндіктер) Бұл сыныпта екі әдіс бар: 1. move()
(ағылшын тілінен move) және 2. attack()
(ағылшынша шабуылдан)
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");
}
}
Енді сіз классты (ағылшынша аары) анықтағыңыз келеді Bee
, оның түрлерінің бірі болып табылады Insect
, бірақ attack()
және әртүрлі іске асырулары бар move()
. Мұны мұраны пайдалану арқылы жасауға болады:
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();
}
}
Класс иерархиялық диаграммасы өте қарапайым: Орындалу нәтижесі:
Fly
Fly
Attack
«Ұшу» екі рет теріледі, сондықтан әдіс move()
екі рет шақырылады. Бірақ оны тек бір рет шақыру керек. Мәселе мынадан туындайды super.attack()
. Әдіс класс әдісін attack ()
шақырады . Ішкі класс шақырғанда , ол қайта анықталған әдісті де шақырады . Мәселені шешу үшін біз: move()
Insect
super.attack ()
move()
- Ішкі класс әдісін жойыңыз
attack()
. Бұл ішкі сыныпты суперсынып әдісін іске асыруға тәуелді етедіattack()
. Егерattack()attack()
суперкласс жылжытудың басқа әдісін қолдана бастаса, ішкі сыныпты да өзгерту қажет болады. Бұл нашар инкапсуляция. -
Әдісті
attack()
келесідей қайта жазыңыз:public void attack() { move(); System.out.println("Attack"); }
-
Бұл дұрыс нәтижеге кепілдік береді, себебі ішкі сынып енді суперклассқа тәуелді емес. Дегенмен, code суперкласстың көшірмесі болып табылады. (әдіс
attack()
жолды шығарудан гөрі күрделірек нәрселерді жасайды). Бұл бағдарламалық жасақтаманың жақсы дизайны емес және қайталанатын code болмауы керек.
2. Құрамы
Мұрагерлік орнына композицияны пайдалануға болады. Оны қолданатын шешімді қарастырайық. Функцияattack()
интерфейс ретінде абстракцияланады.
interface Attack {
public void move();
public void attack();
}
Шабуыл интерфейсін енгізу арқылы шабуылдың әртүрлі түрлерін анықтауға болады.
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);
}
}
Шабуыл функциясы сыртқы болғандықтан, сынып Insect
оны енді қамтымайды.
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;
}
}
Класс Bee
(ағылшын тілінен Bee), тип қалай Insect
шабуыл жасай алады.
// 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();
}
}
Сынып диаграммасы:
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();
}
}
Орындау нәтижесі:
fly
move
fly
sting
3. Бұл тәсілдерді қашан қолдану керек?
Төмендегі 2 тармақ мұра мен құрам арасында шешім қабылдауға көмектеседі:- Егер сіз «IS» пішімінің сыныптары арасындағы қарым-қатынаспен айналысатын болсаңыз және сынып оның барлық интерфейстерін басқа сыныпқа бергісі келсе, мұрагерлік жақсырақ.
- егер қатынас «HAS» болса, онда композицияға артықшылық беріледі.
- Блох, Джошуа. Тиімді java. Pearson Education Үндістан, 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