Richtlinien für die Verwendung von Basisklassen

Eine Klasse ist der am häufigsten verwendete Typ. Eine Klasse kann abstrakt oder versiegelt sein. Für eine abstrakte Klasse muss eine abgeleitete Klasse eine Implementierung bereitstellen. Eine versiegelte Klasse lässt keine abgeleitete Klasse zu. Klassen sind anderen Typen vorzuziehen.

Basisklassen sind eine praktische Möglichkeit, Objekte zu gruppieren, die einen Satz Funktionen gemeinsam verwenden. Basisklassen können einen Standardsatz an Funktionen bereitstellen und gleichzeitig eine Anpassung durch Erweiterung ermöglichen.

Sie sollten einen Konstruktor für eine Klasse explizit bereitstellen. Compiler fügen i. d. R. Klassen, die keinen Konstruktor definieren, einen öffentlichen Standardkonstruktor hinzu. Dies kann einen Benutzer der Klasse irreführend sein, wenn die Klasse nicht zu erstellen sein soll. Es wird daher empfohlen, stets mindestens einen Konstruktor für eine Klasse zu definieren. Markieren Sie den Konstruktor als privat, wenn die Klasse nicht zu erstellen sein soll.

Ergänzen Sie Ihren Entwurf nur dann durch Erweiterbarkeit oder Polymorphie, wenn hierfür ein konkretes Kundenszenario vorliegt. So ist beispielsweise die Bereitstellung einer Schnittstelle für Datenadapter sehr kompliziert, und sie hat keine echten Vorteile. Der Entwickler muss dennoch Code für jeden einzelnen Adapter programmieren, so dass die Bereitstellung der Schnittstelle nur marginale Vorzüge mit sich bringt. Dennoch müssen Sie Konsistenz zwischen allen Adaptern sicherstellen. Obwohl eine Schnittstelle oder eine abstrakte Klasse in dieser Situation nicht geeignet ist, ist die Verwendung eines konsistenten Schemas sehr wichtig. Sie können konsistente Schemas für Entwickler in Basisklassen bereitstellen. Halten Sie sich beim Erstellen von Basisklassen an die folgenden Regeln.

Basisklassen oder Schnittstellen

Ein Schnittstellentyp ist eine Spezifikation eines Protokolls, die potenziell von vielen Objekttypen unterstützt wird. Verwenden Sie, wann immer möglich, Basisklassen anstelle von Schnittstellen. Im Hinblick auf die Versionserstellung sind Klassen flexibler als Schnittstellen. Bei einer Klasse können Sie Version 1.0 ausliefern und dann in Version 2.0 der Klasse eine neue Methode hinzufügen. Sofern die Methode nicht abstrakt ist, funktionieren alle vorhandenen abgeleiteten Klassen weiterhin unverändert.

Da Schnittstellen die Implementierungsvererbung nicht unterstützen, gilt das Schema, das für Klassen zutrifft, nicht ebenso für Schnittstellen. Das Hinzufügen einer Methode zu einer Schnittstelle entspricht dem Hinzufügen einer abstrakten Methode zu einer Basisklasse. Jede Klasse, die die Schnittstelle implementiert, schlägt fehl, da die Klasse die neue Methode nicht implementiert.

Schnittstellen sind in den folgenden Situationen die richtige Wahl:

  • Mehrere nicht zusammengehörige Klassen möchten das Protokoll unterstützen.
  • Diese Klassen haben bereits Basisklassen erstellt (z. B. sind einige UI (User Interface)-Steuerelemente, andere sind XML-Webdienste).
  • Aggregation ist nicht geeignet oder nicht machbar.

In allen anderen Situationen ist die Klassenvererbung das bessere Modell.

Geschützte Methoden und Konstruktoren

Stellen Sie Klassenanpassung durch geschützte Methoden bereit. Die öffentliche Schnittstelle einer Basisklasse sollte dem Consumer der Klasse einen umfassenden Satz an Funktionen zur Verfügung stellen. Häufig jedoch möchten die Benutzer der Klasse die kleinstmögliche Anzahl an Methoden implementieren, die benötigt wird, um dem Consumer diesen umfassenden Satz an Funktionen bereitzustellen. Um diese Anforderung zu erfüllen, stellen Sie einen Satz an nicht-virtuellen oder endgültigen öffentlichen Methoden bereit, die eine einzige geschützte Methode aufrufen, die wiederum Implementierungen für die Methoden bereitstellt. Diese Methode sollte mit dem Impl-Suffix gekennzeichnet werden. Die Verwendung dieses Schemas wird auch als Bereitstellen einer Template-Methode bezeichnet. Dies wird im folgenden Codebeispiel veranschaulicht.

Public Class SampleClass
   
   Private x As Integer
   Private y As Integer
   Private width As Integer
   Private height As Integer
   Private specified As BoundsSpecified
   
   Overloads Public Sub SetBounds(x As Integer, y As Integer, width As 
         Integer, height As Integer)
      SetBoundsImpl(x, y, width, height, Me.specified)
   End Sub 
   
   Overloads Public Sub SetBounds(x As Integer, y As Integer, width As 
         Integer, height As Integer, specified As BoundsSpecified)
      
      SetBoundsImpl(x, y, width, height, specified)
   End Sub 

   Protected Overridable Sub SetBoundsImpl(x As Integer, y As Integer,  
         width As Integer, height As Integer, 
         specified As BoundsSpecified)
      ' Insert code to perform meaningful operations here.
      Me.x = x
      Me.y = y
      Me.width = width
      Me.height = height
      Me.specified = specified      
      Console.WriteLine("x {0}, y {1}, width {2}, height {3}, bounds {4}", 
         Me.x, Me.y, Me.width, Me.height, Me.specified)
   End Sub
End Class 
[C#]
public class MyClass
{
  private int x;
  private int y;
  private int width;
  private int height;
  BoundsSpecified specified;

  public void SetBounds(int x, int y, int width, int height)
   {
      SetBoundsImpl(x, y, width, height, this.specified);
   }

   public void SetBounds(int x, int y, int width, int height,
      BoundsSpecified specified)
   {    
      SetBoundsImpl(x, y, width, height, specified);
   }

   protected virtual void SetBoundsImpl(int x, int y, int width, int 
      height, BoundsSpecified specified)
   {
         // Add code to perform meaningful opertions here.
         this.x = x;
         this.y = y;
         this.width = width;
         this.height = height;
         this.specified = specified;
   }
}

Viele Compiler, z. B. der C#-Compiler, fügen einen public-Konstruktor oder einen protected-Konstruktor ein, sofern Sie dies nicht bereits getan haben. Deshalb sollten Sie, damit der Quellcode besser dokumentiert und leichter lesbar ist, explizit einen protected-Konstruktor für alle abstrakten Klassen definieren.

Richtlinien für die Verwendung von versiegelten Klassen

Verwenden Sie versiegelte Klassen, wenn nur statische Methoden und Eigenschaften für eine Klasse vorhanden sind.

Siehe auch

Entwurfsrichtlinien für die Entwicklung von Klassenbibliotheken | Richtlinien für die Verwendung von Typen | Richtlinien für die Benennung von Klassen