JavaRush /בלוג Java /Random-HE /ירושה לעומת קומפוזיציה בג'אווה
dio
רָמָה
Москва

ירושה לעומת קומפוזיציה בג'אווה

פורסם בקבוצה
מאמר זה ממחיש את המושגים של ירושה והרכב בג'אווה. הדוגמה הראשונה מדגימה ירושה ולאחר מכן מראה כיצד לשפר את עיצוב הירושה באמצעות קומפוזיציה. נסכם בסיום כיצד לבחור ביניהם. ירושה לעומת קומפוזיציה ב-Java - 1

1. ירושה

נניח שיש לנו מחלקה Insect(חרק אנגלי) מחלקה זו מכילה שתי שיטות: 1. 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();
	}
}
דיאגרמת ההיררכיה של המחלקה פשוטה למדי: ירושה לעומת קומפוזיציה ב-Java - 2תוצאת ביצוע:
Fly
Fly
Attack
"זבוב" מוקלד פעמיים, ולכן השיטה move()נקראת פעמיים. אבל צריך לקרוא לזה רק פעם אחת. הבעיה נגרמת על ידי ה super.attack(). השיטה attack ()קוראת ל- move()class method Insect. כאשר תת-מחלקה מתקשרת super.attack (), היא קוראת גם למתודה הדריסה move(). כדי לתקן את הבעיה אנחנו יכולים:
  1. בטל את attack()שיטת המשנה. זה יהפוך את תת-המחלקה לתלויה attack()ביישום השיטה של ​​מחלקת העל. אם attack()attack()מחלקת העל מתחילה להשתמש בשיטה אחרת לתנועה, תת-המחלקה תצטרך להשתנות גם היא. זו אנקפסולציה גרועה.
  2. כתוב מחדש את השיטה attack()באופן הבא:

    public void attack() {
    	move();
    	System.out.println("Attack");
    }
  3. זה מבטיח את התוצאה הנכונה מכיוון שתת-המחלקה אינה תלויה יותר במחלקת העל. עם זאת, הקוד הוא כפיל של מחלקת העל. (השיטה attack()עושה דברים מורכבים יותר מסתם פלט של מחרוזת). זה לא עיצוב תוכנה טוב ולא צריך להיות קוד כפול.

עיצוב הירושה הזה גרוע מכיוון שתת המחלקה תלויה בפרטי היישום של מחלקת העל שלה. אם מחלקת העל משתנה, תת המחלקה לא תעבוד כראוי.

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();
	}
}
דיאגרמת כיתה: ירושה לעומת קומפוזיציה ב-Java - 3
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 הנקודות הבאות יכולות לעזור לך להחליט בין ירושה להרכב:
  1. אם אתה עוסק בקשר בין מחלקות בצורת "IS" ומחלקה רוצה לספק את כל הממשקים שלה למחלקה אחרת, אז תורשה עדיפה.
  2. אם מערכת היחסים היא "HAS", אז ההרכב מועדף.
לפיכך, לירושה ולהרכב יש יישומים משלהם וכדאי להבין את היתרונות שלהם. קישורים:
  1. בלוך, יהושע. Java יעיל. פירסון חינוך הודו, 2008
  2. https://stackoverflow.com/questions/49002/prefer-composition-over-inheritance
  3. https://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition--which-one-should...
קישור למאמר המקורי מתורגם
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION