この章では、オブジェクト指向プログラミング(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.");
}
}
解説
– インターフェースIMovable
はMove
メソッドの契約を定義しており、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
のインスタンスを生成します。
まとめ
この章では、オブジェクト指向プログラミングの応用として、継承、抽象クラスとインターフェース、ポリモーフィズム、カプセル化、デザインパターンの基本について学びました。これらの技術を使うことで、より柔軟で再利用可能なプログラム設計が可能になります。オブジェクト指向の原則を理解し、適切に応用することで、コードの保守性と拡張性が大幅に向上します。
コメント