View on GitHub

maturavorbereitung-2020_21

Fragenkatalog zur Matura in Programmieren (Abendschule) 2020/21

Interfaces

Inhaltsverzeichnis:

Definition

Schnittstellen sind wie eine Vertragsvereinbarung. Sobald eine Klasse eine Schnittstelle implementiert, hat der auf ein Objekt dieser Klasse zugreifende Code die Garantie, dass die Klasse die Member der Schnittstelle aufweist. Mit anderen Worten: Eine Schnittstelle legt einen Vertragsrahmen fest, den die implementierende Klasse erfüllen muss.

Warum Interfaces?

Wenn mehrere Klassen ein gemeinsames Verhalten vorweisen sollen, kann man dies über die Vererbung erreichen.

Das heißt:

Um Verhalten, Eigenschaft, Indexer und Ereignisse unviversell zu machen, muss ein Interface definiert werden.

Schnittstellen unterstützen das Konzept des Information Hiding und sollten möglichst stabil sein. Schnittstellen erlauben es mehreren Teams unabhängig von einander zu arbeiten. Sie erlauben eine Trennung von

Merkmale von Interfaces

Vertrag

Das heißt:

Ziele

Schnittstellendefinition

Interfaces können:

public interface ICopy 
{
  string Caption {get; set;};
  void Copy();
}

Schnittstellenimplementierung

Eine Schnittstelle ist wie ein Vertrag, den eine Klasse unterschreibt, sobald sie eine bestimmte Schnittstelle implementiert.

Das hat Konsequenzen:

Eine Klasse, die eine Schnittstelle implementiert, muss ausnahmslos jedes Mitglied der Schnittstelle übernehmen. Eine zu implementierende Schnittstelle wird, getrennt durch einen Doppelpunkt, hinter dem Klassenbezeichner angegeben. In der Klasse werden alle Member, die aus der Schnittstelle stammen, mit den entsprechenden Anweisungen codiert.

class Document : ICopy {
  public void Copy() {
    Console.WriteLine("Das Dokument wird kopiert.");
  }
  public string Caption {
    get{ [...] }
    set{ [...] }
  }
  [...] 
}

Grundsätzlich kann man jeden beliebigen Code in die Schnittstellenmethoden schreiben. Das ist aber nicht Sinn und Zweck. Stattdessen sollten Sie sich streng daran halten, was die Dokumentation beschreibt. Das bedeutet im Umkehrschluss aber auch, dass eine Schnittstelle ohne Dokumentation wertlos ist. Nur die Dokumentation gibt Auskunft darüber, was eine Methode leisten soll und wie ihre Rückgabewerte zu interpretieren sind.

Eine Klasse ist nicht nur auf die Implementierung einer Schnittstelle beschränkt, es dürfen – im Gegensatz zur Vererbung – auch mehrere sein, die durch ein Komma voneinander getrennt werden.

class Document : ICopy, IDisposable {
  [...]
}

Contract-First-Design

Beim Contract-First-Design werden zuerst die Funkionalitäten des Interfaces definiert und danach erst die Funktionalitäten in der Klasse implementiert.

Dadurch wird sichergestellt, dass alle Klassen die selben Funktionalitäten aufweisen, den selben Vertrag “unterschreiben”. –> Polymorphie

Schnittstellen als Ersatz exakter Typangaben

Bsp.:

   public DoSomething(IAny parameter){
       parameter.Action();
   }

Der Parameter ist vom Typ der Schnittstelle IAny.

Der Parameter verlangt, dass das ihm übergebene Argument ein Objekt ist, das die Schnittstelle IAny implementiert – egal, ob das Objekt vom Typ DemoClass, Circle, Auto oder Person ist.

Einsatzgebiete

Interfaces werden bei eine Core Projekt, Persistence aber auch für Web Projekte verwendet.

Technische Details

Was sind die Unterschiede zwischen abstract und interface?

Tables Abstract Class Interface
Prüfung Prüfung während der Kompilierung Prüfung während der Kompilierung
Implementierung Können Implementierungen enthalten Enthalten keine Implementierungen (lediglich deklarationen)
Vererbung Eine Klasse kann nur von einer Abstrakten Klasse erben Eine Klasse kann jedoch eine beliebige Anzahl an Interface implementieren
Access Modifier Abstrakte Klassenmember können Zugriffsmodifier enthalten Alle Interface Member sind automatisch public
Erlaubte Member Fields, Properties, Construcotrs, Destructors, Methods, Events, Indexers Properties, Methods, Events, Indexers

Beispiele aus dem .Net-Framework

Beispiel 1:

using System;
namespace Uebung 1
{
  public class EinfacheSchnittstellen
  {
    static void Main(string[] args)
    {
      Mathe m = new Mathe();
      DruckeVersionsInfo(m);
      Console.ReadLine();
    }
    private static void DruckeVersionsInfo(IVersionsInfo vi)
    {
      Console.WriteLine(vi.GetType().ToString());
      Console.WriteLine(vi.GetAutor());
      Console.WriteLine(vi.GetVersion());
    }
  }


  public interface IVersionsInfo
  {
    string GetAutor();
    string GetVersion();
  }


  public class Mathe: IVersionsInfo
  {
    private static string version = "0.0.97.123";
    private static string autor = "Dirk Frischalowski";
    public string GetAutor()
    {
      return autor;
    }
    public string GetVersion()
    {
      return version;
    }
  }
}

Beispiel 2:

using System;
namespace Uebung 2
{
  public class Liste mit Interface
  {
    static void Main(string[] args)
    {
            List<IAnimal> animals = new List<IAnimal>();
            animals.Add(new Dog("Fido"));
            animals.Add(new Cat("Bob"));
            animals.Sort();

            foreach(var animal in animals)
                Console.WriteLine(animal.Describe());
            Console.ReadKey();
    }
  }

  public interface IAnimal{
        string Describe();

        string Name
        {
            get;
            set;
        }
  }

  public class Dog : IAnimal, IComparable
  {
    public Dog(string name){
      Name = name;
    }

    public string Describe()
    {
      return "Hello, I'm a dog and my name is " + this.Name;
    }

    public int CompareTo(object obj)
    {
      if(obj is IAnimal)
      {
        return this.Name.CompareTo((obj as IAnimal).Name);
      }
      else
      {
        return 0;
      }
    }
  }

    public class Cat : IAnimal, IComparable
  {
    public Cat(string name){
      Name = name;
    }

    public string Describe()
    {
      return "Hello, I'm a cat and my name is " + this.Name;
    }

     public int CompareTo(object obj)
    {
      if(obj is IAnimal)
      {
        return this.Name.CompareTo((obj as IAnimal).Name);
      }
      else
      {
        return 0;
      }
    }
  }
}

ICompareable & IComparer

int IComparable.CompareTo(object obj)
{
   car c=(car)obj;
   return String.Compare(this.make,c.make);
}
private class sortYearAscendingHelper : IComparer
{
   int IComparer.Compare(object a, object b)
   {
      car c1=(car)a;
      car c2=(car)b;
      if (c1.year > c2.year)
         return 1;
      if (c1.year < c2.year)
         return -1;
      else
         return 0;
   }
}

IEnumerable & IEnumerator

Enumerable und IEnumerator sind zwei Schnittstellen, die zum Implementieren der Iteration in .NET verwendet werden. In C# implementieren alle Collections wie Listen, Dictionaries usw. die IEnumerable-Schnittstelle. Damit sie iteriert werden können.

Jede Klasse, die die IEnumerable-Schnittstelle implementiert, kann aufgelistet werden. Das heißt, man kann eine foreach-Schleife verwenden, um die Klasse zu durchlaufen.

IEnumerable ist eine Schnittstelle, die eine einzelne Methode GetEnumerator() definiert, die eine IEnumerator-Schnittstelle zurückgibt. Dies funktioniert für den schreibgeschützten Zugriff auf eine Collection, die implementiert, dass IEnumerable mit einer foreach-Schleife verwendet werden kann.

class Items : IEnumerable
{
    private string[] ItemList = new string[10];
    int pointer = 0;

    public void AddItem(string item)
    {
        ItemList[pointer++] = item;
    }

    public void RemoveItem(int index)
    {
        ItemList[index] = "";
    }

    public IEnumerator GetEnumerator()
    {
        return new ItemEnumerator();
    }
}

IEnumerator verfügt über zwei Methoden:

Ein Property:

class ItemEnumerator : IEnumerator
{  
    int index=0;
    string[] ItemList;

    public ItemEnumerator(ref string[] List)
    {
        ItemList = List;
    }

    public object Current => ItemList[index++];  

    public bool MoveNext()
    {
        return index >= ItemList.Length ? false: true;
    }

    public void Reset()
    {
        index = 0;
    }
}

Explizit vs Implizit

Wenn eine Klasse zwei Schnittstellen implementiert, die einen Member mit derselben Signatur enthalten, bewirkt die Implementierung dieses Members in der Klasse, dass beide Schnittstellen diesen Member als ihre Implementierung verwenden.

  public interface IControl
  {
      void Paint();
  }
  public interface ISurface
  {
      void Paint();
  }
  public class SampleClass : IControl, ISurface
  {
      // Both ISurface.Paint and IControl.Paint call this method.
      public void Paint()
      {
          Console.WriteLine("Paint method in SampleClass");
      }
  }

Aufruf:

  SampleClass sample = new SampleClass();
  IControl control = sample;
  ISurface surface = sample;

  // The following lines all call the same method.
  sample.Paint();
  control.Paint();
  surface.Paint();

Wenn zwei Schnittstellenmember nicht dieselbe Funktion durchführen, führt dies zu einer fehlerhaften Implementierung von einer oder beiden Schnittstellen.

Lösung:

public class SampleClass : IControl, ISurface
{
    void IControl.Paint()
    {
        System.Console.WriteLine("IControl.Paint");
    }
    void ISurface.Paint()
    {
        System.Console.WriteLine("ISurface.Paint");
    }
}

Explizit:

  public void CopyTo(Array array, int index)
  {
    throw new NotImplementedException();
  }

Implizit:

  void ICollection.CopyTo(Array array, int index)
  {
      throw new NotImplementedException();
  }