JavaRush /Java Blog /Random-JA /Java における継承と合成
dio
レベル 16
Москва

Java における継承と合成

Random-JA グループに公開済み
この記事では、Java における継承と合成の概念を説明します。最初の例では継承を示し、次に合成を使用して継承設計を改善する方法を示します。選び方については最後にまとめていきます。 Java における継承と構成 - 1

1. 継承

Insectクラス(英語の昆虫)があると仮定しましょう。このクラスには 2 つのメソッドが含まれています: 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) を定義したいとします。これは タイプの 1 つですが、と の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」を 2 回入力するため、メソッドがmove()2 回呼び出されます。ただし、呼び出すのは 1 回だけにしてください。この問題は が原因で発生しますsuper.attack()。このメソッドはクラスメソッドattack ()を呼び出します。サブクラスが呼び出すと、オーバーライドされたメソッドも呼び出されます。この問題を解決するには、次のことができます。 move()Insectsuper.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();
}
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(English 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--どれをすべきか...
元記事へのリンク 翻訳
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION