インターフェイスベースのポリモーフィズムを調べる

完了

インターフェイスベースのポリモーフィズムを使用すると、クラスが実装する必要があるコントラクトを定義できるため、クラスの継承に依存せずにポリモーフィックな動作を実現できます。 インターフェイスは、クラスが実装する必要がある一連のメソッドとプロパティを定義しますが、実装の詳細は提供しません。 クラスは複数のインターフェイスを実装できるため、アプリケーションのさまざまな側面の動作を定義できます。

インターフェイスベースのポリモーフィズムを調べるには、前のユニットの継承ベースのポリモーフィズムシナリオに似たシナリオから始めることができます。

C# でのインターフェイス ベースのポリモーフィズムを示す次のコード サンプルを考えてみましょう。


// Define an interface
public interface ISound
{
    void MakeSound();
}

// Implement the interface in different classes
public class Dog : ISound
{
    public void MakeSound()
    {
        Console.WriteLine("The dog barks.");
    }
}

public class Cat : ISound
{
    public void MakeSound()
    {
        Console.WriteLine("The cat meows.");
    }
}

public class Cow : ISound
{
    public void MakeSound()
    {
        Console.WriteLine("The cow moos.");
    }
}

class Program
{
    static void Main()
    {
        // Create an array of Animal myObjects
        ISound[] myObjects = new ISound[3];

        ISound object1 = new Dog();
        ISound object2 = new Cat();
        ISound object3 = new Cow();

        myObjects[0] = object1;
        myObjects[1] = object2;
        myObjects[2] = object3;

        // Demonstrate polymorphism
        foreach (ISound currentObject in myObjects)
        {
            currentObject.MakeSound();
        }
    }
}

このコード サンプルでは、インターフェイス ベースのポリモーフィズムを示すために、ISound メソッドを含む MakeSound インターフェイスを定義します。 DogCat、および Cow クラスは、ISound メソッドの独自の実装を提供することによって、MakeSound インターフェイスを実装します。 Main メソッドは、ISound オブジェクトの配列を作成し、DogCat、および Cow のインスタンスを配列に割り当てます。 foreach ループは配列を反復処理し、各オブジェクトで MakeSound メソッドを呼び出し、ポリモーフィックな動作を示します。

この時点で、インターフェイスベースのポリモーフィズムは、継承ベースのポリモーフィズムと交換可能に見える可能性があります。 クラス型を追加してサンプル コードを更新すると、違いを示すのに役立ちます。

次の更新されたコード サンプルを考えてみましょう。


// Define an interface
public interface ISound
{
    void MakeSound();
}

// Implement the interface in different classes
public class Dog : ISound
{
    public void MakeSound()
    {
        Console.WriteLine("The dog barks.");
    }
}

public class Cat : ISound
{
    public void MakeSound()
    {
        Console.WriteLine("The cat meows.");
    }
}

public class Cow : ISound
{
    public void MakeSound()
    {
        Console.WriteLine("The cow moos.");
    }
}

public class Doorbell : ISound
{
    public void MakeSound()
    {
        Console.WriteLine("The doorbell rings.");
    }
}

public class CarHorn : ISound
{
    public void MakeSound()
    {
        Console.WriteLine("The car horn honks.");
    }
}

class Program
{
    static void Main()
    {
        // Create an array of Animal myObjects
        ISound[] myObjects = new ISound[3];

        ISound object1 = new Dog();
        ISound object2 = new Cat();
        ISound object3 = new Cow();
        ISound object4 = new Doorbell();
        ISound object5 = new CarHorn();

        myObjects[0] = object1;
        myObjects[1] = object2;
        myObjects[2] = object3;
        myObjects[3] = object4;
        myObjects[4] = object5;

        // Demonstrate polymorphism
        foreach (ISound currentObject in myObjects)
        {
            currentObject.MakeSound();
        }
    }
}

この更新されたサンプル コードには、Doorbell インターフェイスを実装する 2 つの追加クラス (CarHornISound) が含まれています。 これらの追加クラスは、特定のクラス階層に関連付けられていない動作を定義するインターフェイス ベースのポリモーフィズムの柔軟性を示すのに役立ちます。

インターフェイスベースのポリモーフィズムは、クラスが複数のインターフェイスを実装できるようにする、特定の機能のコントラクトを定義するなど、追加の利点を提供します。 インターフェイスを使用して、異なるクラス間で共有できる一般的な動作を定義できるため、共通の基底クラスを必要とせずにポリモーフィズムを有効にすることができます。

1 つのインターフェイスと複数のインターフェイスを持つオブジェクトを示す次のコードを考えてみましょう。


// Define an interface for sound
public interface ISound
{
    void MakeSound();
}

// Define an interface for movement
public interface IMovable
{
    void Move();
}

// Implement the ISound and IMovable interfaces in different classes
public class Dog : ISound, IMovable
{
    public void MakeSound()
    {
        Console.WriteLine("The dog barks.");
    }

    public void Move()
    {
        Console.WriteLine("The dog runs.");
    }
}

public class Cat : ISound, IMovable
{
    public void MakeSound()
    {
        Console.WriteLine("The cat meows.");
    }

    public void Move()
    {
        Console.WriteLine("The cat jumps.");
    }
}

public class Cow : ISound, IMovable
{
    public void MakeSound()
    {
        Console.WriteLine("The cow moos.");
    }

    public void Move()
    {
        Console.WriteLine("The cow walks.");
    }
}

public class Doorbell : ISound
{
    public void MakeSound()
    {
        Console.WriteLine("The doorbell rings.");
    }
}

public class CarHorn : ISound
{
    public void MakeSound()
    {
        Console.WriteLine("The car horn honks.");
    }
}

class Program
{
    static void Main()
    {
        // Create an array of ISound objects
        ISound[] soundObjects = new ISound[5];

        ISound object1 = new Dog();
        ISound object2 = new Cat();
        ISound object3 = new Cow();
        ISound object4 = new Doorbell();
        ISound object5 = new CarHorn();

        soundObjects[0] = object1;
        soundObjects[1] = object2;
        soundObjects[2] = object3;
        soundObjects[3] = object4;
        soundObjects[4] = object5;

        // Demonstrate polymorphism with ISound
        Console.WriteLine("Demonstrating ISound polymorphism:");
        foreach (ISound currentObject in soundObjects)
        {
            currentObject.MakeSound();
        }

        // Create an array of IMovable objects
        IMovable[] movableObjects = new IMovable[3];

        IMovable movableObject1 = new Dog();
        IMovable movableObject2 = new Cat();
        IMovable movableObject3 = new Cow();

        movableObjects[0] = movableObject1;
        movableObjects[1] = movableObject2;
        movableObjects[2] = movableObject3;

        // Demonstrate polymorphism with IMovable
        Console.WriteLine("\nDemonstrating IMovable polymorphism:");
        foreach (IMovable currentObject in movableObjects)
        {
            currentObject.Move();
        }

        // Demonstrate objects with single and multiple interfaces
        Console.WriteLine("\nDemonstrating objects with single and multiple interfaces:");
        Dog dog = new Dog();
        Cat cat = new Cat();
        Cow cow = new Cow();
        Doorbell doorbell = new Doorbell();
        CarHorn carHorn = new CarHorn();

        dog.MakeSound();
        dog.Move();

        cat.MakeSound();
        cat.Move();

        cow.MakeSound();
        cow.Move();

        doorbell.MakeSound();

        carHorn.MakeSound();
    }
}

インターフェイスベースのポリモーフィズムを実装する際の一般的な落とし穴を避ける

目的がインターフェイス ベースのポリモーフィズムである場合は、回避すべき事項と、確認すべき点をいくつか次に示します。

  • 関連のないインターフェイスの実装は避けてください。
  • インターフェイスでの既定の実装は避けてください。 C# ではインターフェイスでの既定の実装が可能ですが、混乱を招き、インターフェイスの目的の明確さが低下する可能性があります。 共有実装では抽象クラスを優先します。
  • インターフェイス階層を過度に複雑にしないようにします。 インターフェイス階層をシンプルにし、深い継承チェーンを回避します。 複雑な階層により、コードの理解と保守が困難になる可能性があります。
  • インターフェイス分離の原則 (ISP) に従っていることを確認します。 ISP は、クライアントが使用しないメソッドに依存することを強制してはならないと述べています。 1 つの大きなインターフェイスではなく、より小さく、より具体的なインターフェイスを作成します。

概要

インターフェイスベースのポリモーフィズムを使用すると、クラスが実装する必要があるコントラクトを定義できるため、クラスの継承に依存せずにポリモーフィックな動作を実現できます。 インターフェイスを実装することで、疎結合とコードの再利用性を促進する柔軟で保守可能なコードを作成できます。 インターフェイスは、異なるクラス間で共有できる一般的な動作を定義する方法を提供します。これにより、共通インターフェイスを介してさまざまな型のオブジェクトを操作できます。 インターフェイスベースのポリモーフィズムを理解することで、時間の経過と同時に保守と進化を容易にするモジュール式の拡張可能なアプリケーションを設計できます。