インターフェース vs 抽象クラス
CoddyのC#ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 26/70。
interface と abstract class は、他の class が従う必要のある契約を定義できますが、それぞれ異なる目的を持ち、利用できる機能も異なります。
interface は、実装を一切持たずに、クラスが何をしなければならないかを定義します。純粋な契約です:
public interface IFlyable
{
void Fly();
}
public class Bird : IFlyable
{
public void Fly()
{
Console.WriteLine("Flapping wings");
}
}abstract classは、契約と共有実装の両方を提供できます。これは部分的な設計図です:
public abstract class Vehicle
{
public string Brand { get; set; }
public void StartEngine()
{
Console.WriteLine("Engine started");
}
public abstract void Drive(); // 実装する必要がある
}
public class Car : Vehicle
{
public override void Drive()
{
Console.WriteLine("Driving on roads");
}
}主な違いは、継承のルールと目的にあります。
class は複数のインターフェースを実装できますが、1つの abstract class からのみ継承できます。
関連のない class が動作を共有する必要がある場合(鳥や飛行機の IFlyable のようなケース)は interface を使用します。関連する class が共通のコードと状態を共有する場合(車両がエンジンの始動メカニズムを共有するようなケース)は abstract class を使用します。
抽象クラスには、メンバーのコンストラクター、フィールド、アクセス修飾子を定義できます。従来、インターフェイスにはこれらを定義できませんでしたが、現代の C# ではデフォルト実装が可能です。
迷ったときは、柔軟性のために interface を優先しましょう。共有実装が必要になった場合でも、後から abstract class を追加できます。
チャレンジ
簡単interface と abstract class のどちらを使うべきかを示すメディアプレーヤーシステムを構築しましょう。関連のないデバイスが interface を通じて再生動作を共有し、関連するメディア型が abstract class を通じて共通の実装を共有する設計を作成します。
コードを4つのファイルに分けて整理します。
IPlayable.cs:Medianamespace にIPlayableという interface を Define します。この interface は、phone、TV、専用の music player など、メディアを再生できるあらゆるものの contract を表します。string を返す単一の methodPlay()を declare します。MediaFile.cs:Medianamespace にMediaFileという abstract class を Define します。これはすべての media file に共通する基盤を表します。Titleproperty(string)と、Durationproperty(秒数を表す int)を持たせます。両方の値を設定する constructor を含めます。"{Title} ({Duration}s)"を返す concrete methodGetInfo()を追加します。また、string を返す abstract methodGetType()も declare します。各メディア型が、それがどの種類の file なのかを Define します。AudioFile.cs:Medianamespace にAudioFileclass を Define し、MediaFileから Inherits してIPlayableを Implements します。Artistproperty(string)を追加します。constructor は title、duration、artist を受け取るようにします。GetType()を override して"Audio"を返します。Play()を Implement し、"Playing audio: {Title} by {Artist}"を返します。Program.cs:main file で、input values を使用してAudioFileを Create します。class の両方の側面を示すため、abstract class から Inherits したGetInfo()とGetType()を呼び出し、その後 interface からのPlay()を呼び出します。audio file をIPlayablevariable に格納し、interface polymorphism を示すためにPlay()をもう一度呼び出します。
3つの input を受け取ります。
- Song title
- Duration in seconds
- Artist name
次の形式で output を Print します。
Info: {GetInfo() result}
Type: {GetType() result}
Direct: {Play() result}
Via Interface: {Play() result from IPlayable variable}たとえば、input が Bohemian Rhapsody、354、Queen の場合、output は次のようになります。
Info: Bohemian Rhapsody (354s)
Type: Audio
Direct: Playing audio: Bohemian Rhapsody by Queen
Via Interface: Playing audio: Bohemian Rhapsody by QueenAudioFile が両方のアプローチの利点を得ていることに注目してください。abstract class から共通の実装(GetInfo())を Inherits すると同時に、IPlayable contract も満たしています。abstract class は関連するメディア型にコードの再利用を提供し、interface は、継承階層を共有していない任意の関連のない class でも "playable" にできるようにします。
自分で試してみよう
using System;
using Media;
class Program
{
public static void Main(string[] args)
{
// 入力値を読み取る
string title = Console.ReadLine();
int duration = Convert.ToInt32(Console.ReadLine());
string artist = Console.ReadLine();
// TODO: 入力値を使用してAudioFileを作成する
// TODO: Info: に続けてGetInfo()の結果を出力する
// TODO: Type: に続けてGetType()の結果を出力する
// TODO: Direct: に続けてPlay()の結果を出力する
// TODO: オーディオファイルをIPlayable変数に格納する
// TODO: Via Interface: に続けてIPlayable変数からPlay()の結果を出力する
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
5ポリモーフィズムとインターフェース
コンパイル時 vs 実行時ポリモーフィズムインターフェース vs 抽象クラス複数のインターフェース明示的なインターフェースアップキャストとダウンキャストまとめ - 図形計算機自分で練習してみよう: C#オンラインコンパイラ