JavaRush /Java-Blog /Random-DE /Vererbung vs. Komposition in Java
dio
Level 16
Москва

Vererbung vs. Komposition in Java

Veröffentlicht in der Gruppe Random-DE
Dieser Artikel veranschaulicht die Konzepte der Vererbung und Zusammensetzung in Java. Das erste Beispiel demonstriert die Vererbung und zeigt dann, wie das Vererbungsdesign mithilfe von Komposition verbessert werden kann. Am Ende werden wir zusammenfassen, wie Sie zwischen ihnen wählen können. Vererbung vs. Komposition in Java - 1

1. Vererbung

Nehmen wir an, wir haben eine Klasse Insect(engl. Insekt). Diese Klasse enthält zwei Methoden: 1. move()(von englisch move) und 2. attack()(von englisch 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");
	}
}
Nun möchten Sie eine Klasse (englisch bee) definieren Bee, die zu den Typen gehört Insect, aber unterschiedliche Implementierungen attack()von und hat move(). Dies kann durch Vererbung erfolgen:
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();
	}
}
Das Klassenhierarchiediagramm ist recht einfach: Vererbung vs. Komposition in Java - 2Ausführungsergebnis:
Fly
Fly
Attack
„Fly“ wird zweimal eingegeben, daher move()wird die Methode zweimal aufgerufen. Es sollte aber nur einmal aufgerufen werden. Das Problem wird durch die verursacht super.attack(). Die Methode attack ()ruft eine move()Klassenmethode auf Insect. Wenn eine Unterklasse aufruft super.attack (), ruft sie auch die überschriebene Methode auf move(). Um das Problem zu beheben, können wir:
  1. Eliminieren Sie die attack()Unterklassenmethode. Dadurch wird die Unterklasse von der attack()Methodenimplementierung der Oberklasse abhängig. Wenn attack()attack()die Oberklasse beginnt, eine andere Methode zum Verschieben zu verwenden, muss sich auch die Unterklasse ändern. Das ist eine schlechte Kapselung.
  2. Schreiben Sie die Methode attack()wie folgt um:

    public void attack() {
    	move();
    	System.out.println("Attack");
    }
  3. Dies garantiert das korrekte Ergebnis, da die Unterklasse nicht mehr von der Oberklasse abhängt. Der Code ist jedoch ein Duplikat der Superklasse. (Die Methode attack()erledigt komplexere Dinge als nur die Ausgabe einer Zeichenfolge). Dies ist kein gutes Softwaredesign und es sollte keinen doppelten Code geben.

Dieses Vererbungsdesign ist schlecht, da die Unterklasse von den Implementierungsdetails ihrer Oberklasse abhängt. Wenn sich die Oberklasse ändert, funktioniert die Unterklasse nicht ordnungsgemäß.

2. Zusammensetzung

Sie können Zusammensetzung anstelle von Vererbung verwenden. Schauen wir uns eine Lösung an, die es verwendet. Die Funktion attack()wird als Schnittstelle abstrahiert.
interface Attack {
	public void move();
	public void attack();
}
Durch die Implementierung der Attack-Schnittstelle können verschiedene Angriffsarten definiert werden.
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);
	}
}
Da die Angriffsfunktion extern ist, Insectenthält die Klasse sie nicht mehr.
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;
	}
}
Klasse Bee(von engl. Bee), wie eine Art Insectangreifen kann.
// 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();
	}
}
Klassen Diagramm: Vererbung vs. Komposition in 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();
	}
}
Ausführungsergebnis:
fly
move
fly
sting

3. Wann sollten diese Ansätze eingesetzt werden?

Die folgenden 2 Punkte können Ihnen bei der Entscheidung zwischen Vererbung und Zusammensetzung helfen:
  1. Wenn es sich um eine Beziehung zwischen Klassen der Form „IS“ handelt und eine Klasse alle ihre Schnittstellen einer anderen Klasse zur Verfügung stellen möchte, ist die Vererbung vorzuziehen.
  2. Wenn die Beziehung „HAS“ ist, wird die Zusammensetzung bevorzugt.
Daher haben Vererbung und Zusammensetzung ihre eigenen Anwendungen und es lohnt sich, ihre Vorzüge zu verstehen. Links:
  1. Bloch, Joshua. Effektives Java. Pearson Education India, 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...
Link zum Originalartikel . Übersetzt
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION