Earn More by Sharing What You Love
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Tim Corey
49分41秒
継承とインターフェースは、オブジェクト指向プログラミング(OOP)の不可欠な要素です。 ティム・コーリーは、ビデオ"Inheritance vs Interfaces in C#:オブジェクト指向プログラミング"では、どのような場合に継承を使用し、どのような場合にインターフェイスを選択するかについて詳しく説明しています。
この記事はTim Coreyのビデオへの包括的なガイドとして役立ちます。 ビデオで提供されている主要な概念、例、コードの説明を分解し、継承とインターフェースの違いや、それぞれを使用するタイミングを強調します。
(0:00)のTimは、まず継承とインターフェースを区別することの重要性を強調します。 彼は、最良の結果を得るために、それぞれの概念をいつ使うべきかを理解する必要性を強調しています。 彼の目的は、間違った単一継承の使い方から始まり、それを修正する例を通して、これを実証することである。
(1:08)で、ティムは.NET 5を使ってシンプルなコンソール・アプリケーションを作成します。彼はこのプロジェクトを "OODemoApp "と名付け、第一の目標は生産可能なコードを作成することではなく、コンセプトを実証することであると説明しています。
Timは(1:55)で継承の基本を掘り下げています。 彼は継承を、基本クラスのプロパティとメソッドが派生クラスに継承されるメカニズムであると定義しています。 彼は、継承は単にコードの再利用や共有のために使うのではなく、論理的な"is-a"関係を確立するために使うべきだと強調している。
キーポイント
(7:52)のTimは、継承の基本的な概念を説明するためにRentalCarクラスを作成します。 このクラスは、フロリダ州マイアミのレンタカー会社のレンタカーを表しています。
public class RentalCar
{
public int RentalId { get; set; }
public string CurrentRenter { get; set; }
public decimal PricePerDay { get; set; }
public int NumberOfPassengers { get; set; }
public void StartEngine()
{
Console.WriteLine("Turn key to ignition setting");
Console.WriteLine("Turn key to on");
}
public void StopEngine()
{
Console.WriteLine("Turn key to off");
}
}Public Class RentalCar
Public Property RentalId As Integer
Public Property CurrentRenter As String
Public Property PricePerDay As Decimal
Public Property NumberOfPassengers As Integer
Public Sub StartEngine()
Console.WriteLine("Turn key to ignition setting")
Console.WriteLine("Turn key to on")
End Sub
Public Sub StopEngine()
Console.WriteLine("Turn key to off")
End Sub
End Classティムは(10:15)で、継承の不適切な使用がどのような問題につながるかを説明しています。 継承の使い方を誤ると、管理や拡張が難しいコードになりかねないことを強調している。 彼は、コードを共有するためだけに継承を使用しないようアドバイスしている。
(10:45)のTimは、車種の列挙を追加している。彼はEnums.csという名前の新しいクラスファイルを作成し、すべての列挙型を一箇所にまとめています。 この列挙は、異なる車のスタイルを区別するのに役立ちます。
// Enums.cs
public enum CarType
{
Hatchback,
Sedan,
Compact
}' Enums.vb
Public Enum CarType
Hatchback
Sedan
Compact
End Enum次に、RentalCar クラスに車のタイプを指定するプロパティを追加します。
public class RentalCar : RentalVehicle
{
public CarType Style { get; set; }
// Other properties and methods
}Public Class RentalCar
Inherits RentalVehicle
Public Property Style As CarType
' Other properties and methods
End Class(12:27)でティムが説明しているように、このレンタル業者はトラックを追加することを決定しました。 彼は、親クラス RentalVehicle を継承する RentalTruck クラスを作成します。
public class RentalTruck : RentalVehicle
{
public TruckType Style { get; set; }
// Other properties and methods
}Public Class RentalTruck
Inherits RentalVehicle
Public Property Style As TruckType
' Other properties and methods
End Class次に、トラック・タイプの新しい列挙型を定義する。
// Enums.cs
public enum TruckType
{
ShortBed,
LongBed
}' Enums.vb
Public Enum TruckType
ShortBed
LongBed
End EnumTimは(15:28)で、2つのプロパティが同じ名前を共有しているからといって、それらが同じであるとは限らないことを強調しています。 彼は、異なる列挙型(自動車はCarType、トラックはTruckType)を意味する可能性のあるStyleプロパティでこれを説明しています。
レンタル業者がボートをレンタルすることになりました。 Timは、RentalBoatクラスを作成することで、これを処理する方法を示します。 当初は、ボートは車やトラックといくつかの特性を共有できるため、何とかなりそうです。
public class RentalBoat : RentalVehicle
{
// Properties and methods specific to boats
}Public Class RentalBoat
Inherits RentalVehicle
' Properties and methods specific to boats
End Classヨットにはエンジンがないため、ヨットの紹介が課題となります。 19:57)のティムは、このシナリオにおける継承の限界を説明している。
public class RentalSailboat : RentalVehicle
{
public override void StartEngine()
{
throw new NotImplementedException("I do not have an engine to start");
}
public override void StopEngine()
{
throw new NotImplementedException("I do not have an engine to stop");
}
}Public Class RentalSailboat
Inherits RentalVehicle
Public Overrides Sub StartEngine()
Throw New NotImplementedException("I do not have an engine to start")
End Sub
Public Overrides Sub StopEngine()
Throw New NotImplementedException("I do not have an engine to stop")
End Sub
End ClassTim は、StartEngine と StopEngine メソッドを基底クラスで仮想化し、これらのメソッドを使用しない派生クラスでオーバーライドできるようにすることを提案しています。
public abstract class RentalVehicle
{
// Common properties
public virtual void StartEngine()
{
Console.WriteLine("Engine started");
}
public virtual void StopEngine()
{
Console.WriteLine("Engine stopped");
}
}Public MustInherit Class RentalVehicle
' Common properties
Public Overridable Sub StartEngine()
Console.WriteLine("Engine started")
End Sub
Public Overridable Sub StopEngine()
Console.WriteLine("Engine stopped")
End Sub
End ClassTimは(21:56)で、継承されたクラスに呼び出されるべきでないメソッドを持つことの落とし穴について説明している。 エンジンを持たないRentalSailboatクラスの例では、RentalVehicleクラスからStartEngineメソッドとStopEngineメソッドを継承しています。 これらのメソッドが意図せずに呼び出された場合、適用できないことを示す例外を投げる必要があるため、この状況は問題につながる可能性があります。
public class RentalSailboat : RentalVehicle
{
public override void StartEngine()
{
throw new NotImplementedException("I do not have an engine to start");
}
public override void StopEngine()
{
throw new NotImplementedException("I do not have an engine to stop");
}
}Public Class RentalSailboat
Inherits RentalVehicle
Public Overrides Sub StartEngine()
Throw New NotImplementedException("I do not have an engine to start")
End Sub
Public Overrides Sub StopEngine()
Throw New NotImplementedException("I do not have an engine to stop")
End Sub
End Class(24:06)のティムは、継承が論理的な意味をなさなくなったとき、いかに複雑で厄介なコードベースになるかを強調している。 たとえば、ヨットをエンジン付きのRentalVehicleとして扱うべきではありません。これは、継承の限界と、より良い設計アプローチの必要性を示しています。
これらの問題に対処するために、ティムはインターフェイスを使ったより良いデザインを提案しています。 彼は、改善されたアプローチを示すために、"BetterOODemo "という新しいコンソール・アプリケーション・プロジェクトを作成することから始めます。
Timは、すべてのレンタルに共通するプロパティをカプセル化するIRentalインターフェイスを紹介します。
public interface IRental
{
int RentalId { get; set; }
string CurrentRenter { get; set; }
decimal PricePerDay { get; set; }
}Public Interface IRental
Property RentalId As Integer
Property CurrentRenter As String
Property PricePerDay As Decimal
End Interfaceティムは次に、陸上車両用の基本クラスを作成し、車両レンタルという概念を車両自体から切り離します。
public abstract class LandVehicle
{
public int NumberOfPassengers { get; set; }
public virtual void StartEngine()
{
Console.WriteLine("Engine started");
}
public virtual void StopEngine()
{
Console.WriteLine("Engine stopped");
}
}Public MustInherit Class LandVehicle
Public Property NumberOfPassengers As Integer
Public Overridable Sub StartEngine()
Console.WriteLine("Engine started")
End Sub
Public Overridable Sub StopEngine()
Console.WriteLine("Engine stopped")
End Sub
End Classベースとなる車両クラスの名前を LandVehicle に変更することで、Tim は適切な車両のみがエンジン関連のメソッドを継承するようにします。
Timは、LandVehicleを継承し、IRentalインタフェースを実装するCarクラスとTruckクラスを作成します。
public class Car : LandVehicle, IRental
{
public int RentalId { get; set; }
public string CurrentRenter { get; set; }
public decimal PricePerDay { get; set; }
public CarType Style { get; set; }
}
public class Truck : LandVehicle, IRental
{
public int RentalId { get; set; }
public string CurrentRenter { get; set; }
public decimal PricePerDay { get; set; }
public TruckType Style { get; set; }
}Public Class Car
Inherits LandVehicle
Implements IRental
Public Property RentalId As Integer Implements IRental.RentalId
Public Property CurrentRenter As String Implements IRental.CurrentRenter
Public Property PricePerDay As Decimal Implements IRental.PricePerDay
Public Property Style As CarType
End Class
Public Class Truck
Inherits LandVehicle
Implements IRental
Public Property RentalId As Integer Implements IRental.RentalId
Public Property CurrentRenter As String Implements IRental.CurrentRenter
Public Property PricePerDay As Decimal Implements IRental.PricePerDay
Public Property Style As TruckType
End Classこの設計では、各クラスがその型に関連するプロパティとメソッドのみを持つようにし、明確な関係分離を維持します。
Timは(31:41)で、不必要なコードの重複を避けることの重要性について述べています。 IRentalインターフェイスは複数のクラスで同じプロパティを必要とするが、これはDRY(Don't Repeat Yourself)原則の違反とは見なされない。
(35:09)のTimは、LandVehicleを継承する代わりにIRentalインターフェースを実装することで、RentalSailboatクラスを個別に処理する方法を説明しています。 このアプローチは、不適切な継承に伴う落とし穴を避けるのに役立ちます。
public class Sailboat : IRental
{
public int RentalId { get; set; }
public string CurrentRenter { get; set; }
public decimal PricePerDay { get; set; }
// Additional properties and methods specific to sailboats
}Public Class Sailboat
Implements IRental
Public Property RentalId As Integer
Public Property CurrentRenter As String
Public Property PricePerDay As Decimal
' Additional properties and methods specific to sailboats
End ClassTimは、トラック、ヨット、車などのさまざまなレンタルタイプを保存するためにIRentalインターフェイスを利用して、さまざまなタイプのレンタルを管理するためのリストを設定します。
List<IRental> rentals = new List<IRental>
{
new Truck { CurrentRenter = "Truck Renter" },
new Sailboat { CurrentRenter = "Sailboat Renter" },
new Car { CurrentRenter = "Car Renter" }
};Dim rentals As New List(Of IRental) From {
New Truck With {.CurrentRenter = "Truck Renter"},
New Sailboat With {.CurrentRenter = "Sailboat Renter"},
New Car With {.CurrentRenter = "Car Renter"}
}この設計により、レンタルをループしてRentalIdのような共通プロパティにアクセスすることができます。
foreach (var rental in rentals)
{
Console.WriteLine($"Renter: {rental.CurrentRenter}, Price Per Day: {rental.PricePerDay}");
}For Each rental In rentals
Console.WriteLine($"Renter: {rental.CurrentRenter}, Price Per Day: {rental.PricePerDay}")
Next異なるレンタルタイプの特定のプロパティとメソッドにアクセスするために、Tim はisキーワードを使用してオブジェクトをそれぞれの型にチェックしキャストする方法を示します。
foreach (var rental in rentals)
{
if (rental is Truck truck)
{
Console.WriteLine($"Truck Style: {truck.Style}, Passengers: {truck.NumberOfPassengers}");
}
else if (rental is Sailboat sailboat)
{
// Access sailboat-specific properties
}
else if (rental is Car car)
{
// Access car-specific properties
}
}For Each rental In rentals
If TypeOf rental Is Truck Then
Dim truck As Truck = CType(rental, Truck)
Console.WriteLine($"Truck Style: {truck.Style}, Passengers: {truck.NumberOfPassengers}")
ElseIf TypeOf rental Is Sailboat Then
Dim sailboat As Sailboat = CType(rental, Sailboat)
' Access sailboat-specific properties
ElseIf TypeOf rental Is Car Then
Dim car As Car = CType(rental, Car)
' Access car-specific properties
End If
Nextティムは、インターフェイスを使用することで、将来の変更に柔軟に対応できることを強調しています。 例えば、戦車やテレビのような新しいタイプのレンタルを追加しても、既存の構造が崩れることはありません。
Timは、コード共有のために継承を使いすぎると、複雑で融通の利かないコードベースになる可能性があることを忠告しています。 その代わりに、"is-a"関係を論理的な範囲を超えて引き伸ばすことなく、望ましい結果を達成するためにインターフェースとコンポジションを活用することを勧めている。
ティム・コーリーによるOOPにおける継承とインターフェースの説明は、保守可能で柔軟なコードを作成するための明確な道筋を提供します。 よくある落とし穴を紹介し、洗練されたデザインのインターフェイスを提供することで、開発者がアプリケーションを効果的に構成するために、十分な情報に基づいた決定を下せるようにする。
これらのコンセプトをより深く掘り下げ、実際に使用している様子を見るには、ティムの完全なビデオをご覧ください。 チャンネルは、プログラミング・チュートリアルの宝庫です。 お見逃しなく!
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!
Join our newsletter, you’ll get exclusive access on article updates. We value your privacy