Utforska gränssnittsbaserad polymorfism

Fullbordad

Med gränssnittsbaserad polymorfism kan du definiera ett kontrakt som klasser måste implementera, så att du kan uppnå polymorft beteende utan att förlita dig på klassarv. Gränssnitt definierar en uppsättning metoder och egenskaper som en klass måste implementera, men ger ingen implementeringsinformation. Klasser kan implementera flera gränssnitt så att de kan definiera beteende för olika aspekter av programmet.

Om du vill utforska gränssnittsbaserad polymorfism kan du börja med ett scenario som liknar det arvsbaserade polymorfismscenariot från föregående lektion.

Tänk dig följande kodexempel som visar gränssnittsbaserad polymorfism i 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();
        }
    }
}

I det här kodexemplet demonstreras gränssnittsbaserad polymorfism genom att definiera ett ISound gränssnitt som innehåller en MakeSound-metod. Klasserna Dog, Catoch Cow implementerar ISound-gränssnittet genom att tillhandahålla egna implementeringar av metoden MakeSound. Metoden Main skapar en matris med ISound objekt och tilldelar instanser av Dog, Catoch Cow till matrisen. Den foreach-loopen itererar över matrisen och anropar metoden MakeSound för varje objekt, vilket visar polymorfiskt beteende.

Nu kan gränssnittsbaserad polymorfism verka utbytbar med arvsbaserad polymorfism. Om du uppdaterar exempelkoden med tilläggsklasstypen kan du visa skillnaden.

Överväg följande uppdaterade kodexempel:


// 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();
        }
    }
}

Den uppdaterade exempelkoden innehåller ytterligare två klasser, Doorbell och CarHorn, som implementerar ISound-gränssnittet. Dessa ytterligare klasser hjälper till att demonstrera gränssnittsbaserad polymorfisms större flexibilitet när det gäller att definiera beteenden som inte är knutna till en specifik klasshierarki.

Gränssnittsbaserad polymorfism ger ytterligare fördelar, till exempel att tillåta klasser att implementera flera gränssnitt och definiera kontrakt för specifika funktioner. Gränssnitt kan användas för att definiera vanliga beteenden som kan delas mellan olika klasser, vilket möjliggör polymorfism utan behov av en gemensam basklass.

Tänk på följande kod som visar objekt med enkla och flera gränssnitt:


// 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();
    }
}

Undvik vanliga fallgropar när du implementerar gränssnittsbaserad polymorfism

När ditt mål är gränssnittsbaserad polymorfism, här är några saker att undvika och några saker att säkerställa:

  • Undvik att implementera orelaterade gränssnitt.
  • Undvik standardimplementeringar i gränssnitt. C# tillåter standardimplementeringar i gränssnitt, men det kan leda till förvirring och minska tydligheten i gränssnittets syfte. Föredrar abstrakta klasser för delade implementeringar.
  • Undvik att överkomplicera gränssnittshierarkier. Håll gränssnittshierarkier enkla och undvik djupa arvskedjor. Komplexa hierarkier kan göra koden svårare att förstå och underhålla.
  • Se till att du följer principen för gränssnittssegregering (ISP). Isp anger att ingen klient ska tvingas att vara beroende av metoder som den inte använder. Skapa mindre, mer specifika gränssnitt i stället för ett stort gränssnitt.

Sammanfattning

Med gränssnittsbaserad polymorfism kan du definiera kontrakt som klasser måste implementera, så att du kan uppnå polymorft beteende utan att förlita dig på klassarv. Genom att implementera gränssnitt kan du skapa flexibel och underhållsbar kod som främjar lös koppling och återanvändning av kod. Gränssnitt är ett sätt att definiera vanliga beteenden som kan delas mellan olika klasser, så att du kan arbeta med objekt av olika typer via ett gemensamt gränssnitt. Genom att förstå gränssnittsbaserad polymorfism kan du utforma modulära och utökningsbara program som är enklare att underhålla och utveckla över tid.