JavaRush /จาวาบล็อก /Random-TH /การสืบทอดและองค์ประกอบใน Java
dio
ระดับ
Москва

การสืบทอดและองค์ประกอบใน Java

เผยแพร่ในกลุ่ม
บทความนี้แสดงแนวคิดเกี่ยวกับการสืบทอดและองค์ประกอบใน Java ตัวอย่างแรกแสดงให้เห็นถึงการสืบทอด จากนั้นจะแสดงวิธีปรับปรุงการออกแบบการสืบทอดโดยใช้องค์ประกอบ เราจะสรุปวิธีการเลือกระหว่างพวกเขาในตอนท้าย การสืบทอดเทียบกับองค์ประกอบใน 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(English 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
พิมพ์ "Fly" สองครั้ง ดังนั้นmove()จึงเรียกเมธอดนี้สองครั้ง แต่ควรจะเรียกเพียงครั้งเดียว ปัญหามีสาเหตุมาจากsuper.attack(). วิธีการattack ()เรียกวิธีmove()การเรียน 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. โบลช, โจชัว. ชวาที่มีประสิทธิภาพ เพียร์สันเอ็ดดูเคชั่นอินเดีย, 2551
  2. https://stackoverflow.com/questions/49002/prefer-composition-over-inheritance
  3. https://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition--who-one-should...
ลิงก์ไปยังบทความต้นฉบับ ที่แปลแล้ว
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION