【学習】ターン制バトルで学ぶオブジェクト指向(4)Character で共通化 〜abstract と継承〜
第3回で Warrior と Mage は 名前・HP・GetPower() という共通の形を持っていました。
ここで 共通部分だけ を親クラスにまとめ、違う部分だけ を子クラスに書き分けます。
今回の最小ゴール
Characterをabstractクラス として定義し、NameとHpを共有するGetPower()は シグネチャだけ親 に書き、中身は子でoverrideWarrior/Mageを 継承 で書き直す
前回からの差分
abstract class Characterを新設Warrior/Mageは: Characterで継承し、: base(name, hp)で親コンストラクタを呼ぶpublic abstract int GetPower();とpublic override int GetPower()を初めて使う
ソリューションとプロジェクトを作る
- テンプレート: コンソール アプリ
- プロジェクト名:
TurnBattleOop04(任意)
親クラス Character
共通だけ を決めます。GetPower() は 子ごとに違う ので、親では 宣言だけ にします。
public abstract class Character
{
public string Name { get; set; }
public int Hp { get; set; }
public Character(string name, int hp)
{
Name = name;
Hp = hp;
}
public abstract int GetPower();
}abstractメソッド … 親は「こういうメソッドがある」とだけ決め、実装は書かないabstractクラス … このままではnew Character(...)はできない(不完全な設計図)
子クラス Warrior
public class Warrior : Character
{
public int Strength { get; set; }
public Warrior(string name, int hp, int strength)
: base(name, hp)
{
Strength = strength;
}
public override int GetPower()
{
return Strength + Strength / 2;
}
}: base(name, hp) で、親の Name と Hp を初期化します。
子クラス Mage
public class Mage : Character
{
public int Magic { get; set; }
public Mage(string name, int hp, int magic)
: base(name, hp)
{
Magic = magic;
}
public override int GetPower()
{
return Magic + Magic / 2;
}
}Main で動作確認
internal class Program
{
private static void Main(string[] args)
{
Warrior warrior = new Warrior("せんし", 100, 20);
Mage mage = new Mage("まどうし", 80, 25);
Console.WriteLine(warrior.Name + "の攻撃力:" + warrior.GetPower());
Console.WriteLine(mage.Name + "の攻撃力:" + mage.GetPower());
}
}第3回と表示は同じでも、中身の整理 が違います。
プログラムの流れ(設計の見方)
Character が Name / Hp と GetPower() の約束を決める
↓
Warrior / Mage が実際の GetPower() を実装する
↓
呼び出し側は「種類ごとの細部」をまだ気にしない(次回)WinForms / Unity での当たり所
| 要素 | 意味 |
|---|---|
親 Character |
敵・味方の 共通ステータス の置き場 |
abstract |
「種類ごとに必ず実装して」という ルール |
override |
種類別の 具体的な計算・挙動 |
重要ポイント
- 継承は難しい魔法ではなく、重複を減らす整理 と捉える
- 共通は親、違いは子 が基本形
abstractは 「最初から書く」ものではなく、重複が見えてから導入 してよい