第7章: オブジェクト指向の応用

csharp-oop-advanced-guide

この章では、オブジェクト指向プログラミング(OOP)の基本を発展させ、C#におけるオブジェクト指向の重要な概念である継承抽象クラスインターフェースポリモーフィズムカプセル化デザインパターンなどについて詳しく説明します。これらの概念を理解し、効果的に使うことで、より柔軟で再利用可能なコードを作成できるようになります。

7.1 継承と派生クラスの作成

継承は、あるクラスが別のクラスのプロパティやメソッドを引き継ぐ仕組みです。これにより、共通の機能を複数のクラスで再利用でき、コードの重複を避けることができます。

継承の基本構文

public class Animal
{
    public string Name { get; set; }

    public void Speak()
    {
        Console.WriteLine($"{Name} makes a sound.");
    }
}

public class Dog : Animal
{
    public void Bark()
    {
        Console.WriteLine($"{Name} barks.");
    }
}

解説

DogクラスはAnimalクラスを継承しています。このため、DogクラスはNameプロパティとSpeakメソッドを引き継ぎます。

Dogクラスには新たにBarkメソッドが追加されています。

使用例

Dog dog = new Dog();
dog.Name = "Rex";
dog.Speak();  // 出力: Rex makes a sound.
dog.Bark();   // 出力: Rex barks.

継承の利点

– 継承により、コードの再利用性が向上し、基底クラスに共通の機能をまとめることで、変更や拡張が容易になります。

7.2 抽象クラスとインターフェースの違いと使用法

抽象クラスインターフェースは、オブジェクト指向プログラミングにおいて、設計の柔軟性を高めるために使用されます。どちらもメソッドやプロパティの宣言を含みますが、具体的な実装は派生クラスや実装クラスに任せます。

抽象クラス

public abstract class Shape
{
    public string Color { get; set; }

    public abstract double GetArea(); // 抽象メソッド
}

public class Circle : Shape
{
    public double Radius { get; set; }

    public override double GetArea() // 抽象メソッドの実装
    {
        return Math.PI * Radius * Radius;
    }
}

解説

Shapeクラスは抽象クラスであり、GetAreaメソッドが抽象メソッドとして定義されています。このメソッドは派生クラスで実装されなければなりません。

Circleクラスでは、GetAreaメソッドを具体的に実装しています。

インターフェース

public interface IMovable
{
    void Move();
}

public class Car : IMovable
{
    public void Move()
    {
        Console.WriteLine("The car moves.");
    }
}

解説

– インターフェースIMovableMoveメソッドの契約を定義しており、Carクラスはその契約に従ってMoveメソッドを実装します。

– インターフェースを使用することで、複数のクラスが同じ契約(メソッドやプロパティ)を実装できるようになります。

7.3 ポリモーフィズムと仮想メソッド (virtual, override, new)

ポリモーフィズムは、同じインターフェースやメソッドを使って異なる型のオブジェクトを扱う仕組みです。これにより、プログラムの柔軟性が大幅に向上します。

仮想メソッドとオーバーライド

public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("The animal makes a sound.");
    }
}

public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("The dog barks.");
    }
}

解説

AnimalクラスのSpeakメソッドはvirtualキーワードで定義されており、派生クラスでオーバーライド可能です。

DogクラスではSpeakメソッドをオーバーライドして、新しい実装を提供しています。

使用例

Animal myAnimal = new Animal();
myAnimal.Speak();  // 出力: The animal makes a sound.

Animal myDog = new Dog();
myDog.Speak();     // 出力: The dog barks.

7.4 カプセル化の原則とプロパティの使用

カプセル化は、オブジェクトの内部データを隠蔽し、外部から直接アクセスできないようにすることです。これにより、データの整合性を保ち、意図しない変更を防ぎます。C#では、フィールドをprivateにして、publicなプロパティを使ってアクセスを制御することが一般的です。

カプセル化の例

public class BankAccount
{
    private decimal balance; // プライベートフィールド

    public decimal Balance   // パブリックプロパティ
    {
        get { return balance; }
        private set
        {
            if (value >= 0)
            {
                balance = value;
            }
        }
    }

    public void Deposit(decimal amount)
    {
        if (amount > 0)
        {
            Balance += amount;
        }
    }
}

解説

balanceフィールドはprivateで定義されており、外部から直接アクセスできません。

Balanceプロパティは、getアクセサを使って残高を取得し、setアクセサをprivateにして内部でのみ値を設定できるようにしています。

Depositメソッドを使って残高を追加しますが、負の金額は追加できないようになっています。

7.5 デザインパターンの基本 (Singleton, Factoryなど)

デザインパターンは、一般的なプログラム設計の問題を解決するための再利用可能な解決策です。C#でよく使われるデザインパターンとして、SingletonパターンFactoryパターンがあります。

Singletonパターン

public class Singleton
{
    private static Singleton instance;

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
}

解説

Singletonクラスでは、コンストラクタをprivateにして外部からのインスタンス化を防いでいます。

Instanceプロパティを使って、クラスの唯一のインスタンスを取得します。

Factoryパターン

public abstract class Product
{
    public abstract void Use();
}

public class ConcreteProductA : Product
{
    public override void Use() => Console.WriteLine("Using Product A");
}

public class ConcreteProductB : Product
{
    public override void Use() => Console.WriteLine("Using Product B");
}

public class ProductFactory
{
    public static Product CreateProduct(string type)
    {
        return type switch
        {
            "A" => new ConcreteProductA(),
            "B" => new ConcreteProductB(),
            _ => throw new ArgumentException("Invalid type")
        };
    }
}

解説

ProductFactoryクラスは、クライアントが具体的な製品クラスを意識せずにオブジェクトを作成できるようにします。

CreateProductメソッドは、typeに基づいてConcreteProductAまたはConcreteProductBのインスタンスを生成します。

まとめ

この章では、オブジェクト指向プログラミングの応用として、継承、抽象クラスとインターフェース、ポリモーフィズム、カプセル化、デザインパターンの基本について学びました。これらの技術を使うことで、より柔軟で再利用可能なプログラム設計が可能になります。オブジェクト指向の原則を理解し、適切に応用することで、コードの保守性と拡張性が大幅に向上します。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次