トラック
/
C#
C#
/
演習
/
魔法使いと戦士
魔法使いと戦士

魔法使いと戦士

学習演習

はじめに

継承

C#では、_継承_を使って_クラス_の階層を定義できます。継承を使うと、派生クラス(Car)が親クラス(Vehicle)の振る舞いとデータを引き継げます。親クラスを指定しない場合、そのクラスはobjectクラスを継承します。

親クラスは、次の3つの方法で派生クラスに機能を提供できます。

  • 通常のメソッドを定義します。
  • virtualメソッドを定義します。これは通常のメソッドに似ていますが、派生クラスが変更_できる_メソッドです。
  • abstractメソッドを定義します。これは実装を持たないメソッドで、派生クラスが必ず実装しなければならないものです。abstractメソッドを持つクラスは、そのクラス自体もabstractとしてマークする必要があります。抽象クラスはインスタンス化できません。

protectedアクセス修飾子を使うと、親クラスのメンバーに派生クラスからアクセスできますが、他のクラスからはアクセスできません。

派生クラスは、baseキーワードを通じて親クラスのメンバーにアクセスできます。

// Inherits from the 'object' class
abstract class Vehicle
{
    // Can be overridden
    public virtual void Drive()
    {
    }

    // Must be overridden
    protected abstract int Speed();
}

class Car : Vehicle
{
    public override void Drive()
    {
        // Override virtual method

        // Call parent implementation
        base.Drive();
    }

    protected override int Speed()
    {
        // Implement abstract method
    }
}

派生クラスのコンストラクターは、自身のコンストラクターの処理を実行する_前に_、親クラスのコンストラクターを自動的に呼び出します。親クラスのコンストラクターには、baseキーワードを使って引数を渡せます。

abstract class Vehicle
{
    protected Vehicle(int wheels)
    {
        Console.WriteLine("Called first");
    }
}

class Car : Vehicle
{
    public Car() : base(4)
    {
        Console.WriteLine("Called second");
    }
}

複数のクラスが1つの基底クラスから派生している場合、それら2つ(またはそれ以上)のクラスは、基底クラスのメソッドに対してしばしば異なるバージョンを実装します。これはポリモーフィズムと呼ばれる、とても重要な原則です。たとえば、上の例を少し変えた次の例では、Vehicleを使うコードが、どの種類の乗り物がインスタンス化されたかに応じて振る舞いを変えられることを示しています。

abstract class Vehicle
{
   public abstract string GetDescription();
}

class Car : Vehicle
{
   public Car()
   {
   }

   public override string GetDescription()
   {
      return "Runabout";
   }
}

class Rig : Vehicle
{
   public Rig()
   {
   }

   public override string GetDescription()
   {
      return "Big Rig";
   }
}

Vehicle v1 = new Car();
Vehicle v2 = new Rig();

v1.GetDescription();
// => Runabout
v2.GetDescription();
// => Big Rig

説明

この演習では、「Wizard and Warriors」という名前のロールプレイングゲームで遊びます。WizardかWarriorのどちらかとしてプレイできます。

WarriorとWizardでは、与えるダメージポイントを決めるルールが異なります。

Warriorのルールは次のとおりです。

  • 攻撃対象のキャラクターが脆弱でない場合は、6ポイントのダメージを与えます
  • 攻撃対象のキャラクターが脆弱な場合は、10ポイントのダメージを与えます

Wizardのルールは次のとおりです。

  • Wizardが事前に呪文を準備している場合は、12ポイントのダメージを与えます
  • Wizardが事前に呪文を準備していない場合は、3ポイントのダメージを与えます

通常、キャラクターが脆弱になることはありません。ただし、Wizardは呪文を準備していない場合、脆弱になります。

WarriorとWizardのキャラクターを扱う6つのタスクがあります。

1. キャラクターを説明する

CharacterクラスのToString()メソッドをオーバーライドして、キャラクターの説明を"Character is a <CHARACTER_TYPE>"という形式で返すようにします。

var warrior = new Warrior();
warrior.ToString();
// => "Character is a Warrior"

2. キャラクターがデフォルトで脆弱にならないようにする

Character.Vulnerable()メソッドが常にfalseを返すようにします。

var warrior = new Warrior();
warrior.Vulnerable();
// => false

3. Wizardが呪文を準備できるようにする

Wizard.PrepareSpell()メソッドを実装して、Wizardが事前に呪文を準備できるようにします。

var wizard = new Wizard();
wizard.PrepareSpell();

4. 呪文を準備していないWizardを脆弱にする

Wizardが呪文を準備していない場合は、Vulnerable()メソッドがtrueを返すようにします。それ以外の場合はfalseを返します。

var wizard = new Wizard();
wizard.Vulnerable();
// => true

5. Wizardのダメージポイントを計算する

Wizard.DamagePoints()メソッドを実装して、与えるダメージポイントを返すようにします。呪文を準備している場合は12ダメージポイント、準備していない場合は3ダメージポイントです。

var wizard = new Wizard();
var warrior = new Warrior();

wizard.PrepareSpell();
wizard.DamagePoints(warrior);
// => 12

6. Warriorのダメージポイントを計算する

Warrior.DamagePoints()メソッドを実装して、与えるダメージポイントを返すようにします。対象が脆弱な場合は10ダメージポイント、脆弱でない場合は6ダメージポイントです。

var warrior = new Warrior();
var wizard = new Wizard();

warrior.DamagePoints(wizard);
// => 10
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
C# Exercism

魔法使いと戦士を始める準備はできましたか?

Exercismに登録すれば、62個のコンセプト178個の演習、そして本物の人間によるメンタリングとともに、C#を学んでマスターできます。すべて無料です。