Start
Methodik
Unternehmen



Comelio GmbHBerlin
Fon: +49(0)30-3640339-80
Fax: +49(0)30-3640339-89
info@comelio.com

Comelio GmbHEssen
Fon: +49(0)201-437517-0
Fax: +49(0)201-437517-10
info@comelio.com

Comelio GmbHMünchen
Fon: +49(0)89-38156860-0
Fax: +49(0)89-38156860-9
info@comelio.com

Comelio GmbHWien
Fon: +43-720-2097-97
Fax: +43-720-2097-98
info@comelio.com

Comelio GmbHZürich
info@comelio.com










Comelio-Blog > C#.NET > Adapter-Muster

Entwurfsmuster (Design Patterns) in C#.NET: Adapter

Das Adapter-Muster stellt die Lösung für eine Problemsituation dar, in der man sehr gerne eine vorhandene Klasse nutzen möchte, ihre öffentlichen Komponenten allerdings nicht zu einer vorliegenden Schnittstelle passen. Dadurch lässt sich kein polymorphes Verhalten nutzen, sondern man müsste quasi eine neue Klasse erstellen, die die benötigte Schnittstelle implementiert und kann auf die vorliegende Klasse dann doch wiederum ohne Änderungen nicht zurückzugreifen. Dieser Artikel gibt eine beispielhafte Implementierung mit C#.NET an.

Kontakt

Anrede* Herr Frau
Vorname*
Nachname*
Firma
E-Mail*
Tel-Nr.
Bereich*
Freitext

Design Patterns: Adapter-Muster in C#.NET

Wie auch das Singleton-Muster, so ist auch das Adapter-Muster sowohl leicht erlernbar, einfach zu implementieren und oft einzusetzen. Typische Einsatzgebiete sind solche Projekte, in denen mit bereits fertigen Klassen gearbeitet werden soll, die allerdings nicht in die schöne, durch Schnittstellen oder abstrakte Klassen vorbereitet Ordnung passen wollen, sondern die für den Einsatz erst noch zurechtgestutzt werden sollen. Dabei ist es typischerweise nicht möglich, tatsächlich die Klassen zu ändern, weil sie entweder genau in der vorliegenden Weise bereits in diesem oder anderen Projekten bzw. Anwendungen genutzt werden, oder weil eine Änderung aufgrund fehlender Quelltextbearbeitungsmöglichkeit gar nicht durchgeführt werden kann.

Das Adapter-Muster stellt die Lösung für eine Problemsituation dar, in der man sehr gerne eine vorhandene Klasse nutzen möchte, ihre öffentlichen Komponenten allerdings nicht zu einer vorliegenden Schnittstelle passen. Dadurch lässt sich kein polymorphes Verhalten nutzen, sondern man müsste quasi eine neue Klasse erstellen, die die benötigte Schnittstelle implementiert und kann auf die vorliegende Klasse dann doch wiederum ohne Änderungen nicht zurückzugreifen.

Selbstverständlich wird die vorliegende Klasse aus unterschiedlichen Gründen gerade nicht geändert, sondern wird eine umhüllende Klasse erstellt, die exakt die geforderte Schnittstelle implementiert und daher das polymorphe Verhalten umsetzt. Innerhalb dieser umhüllenden Klasse, die als Adapter fungiert, erzeugt man nun das eigentlich benötigte Objekt der bereits vorhandenen Klasse und formt Methoden- oder Feld-/Eigenschaftsnamen, Parameterlisten und Rückgabewerte so passend um, bis man wie bei einem Adapter sowohl die Schnittstellenbedingungen erfüllt als auch der bereits vorliegenden Klasse Genüge getan hat.

public interface IKoerper {
   // Eigenschaften
   int laenge { get; }
   int breite { get; }
   int hoehe  { get; }
   // Methoden
   double errechneFlaeche();
}
Schnittstelle IKoerper

Ein Beispiel soll dieses recht einfache Vorgehen illustrieren. Aus nicht näher bekannten Gründen soll in die bereits bestehenden Formen eine weitere Form für die Abbildung eines Kreiszylinders eingefügt werden. Anstatt nun diese Klasse von Grund auf neu zu erstellen, stellt man fest, dass bereits eine von ihrer Implementierung, aber nicht von ihren öffentlichen Komponenten her nutzbare Klasse vorliegt. Diese heißt RundZylinder, speichert hoehe und breite als Felder und nicht als Eigenschaften und liefert die Fläche nicht als Methode unter dem Namen errechneFlaeche, sondern als Eigenschaft flaeche. Dennoch ist die komplizierte Formel zur Berechnung derselben genauso implementiert wie man sie für die Methode errechneFlaeche der IKoerper-Schnittstelle benutzen könnte. Diese Klasse soll benutzt werden, kann allerdings in der vorliegenden Form nicht zum Einsatz kommen, weil sie die IKoerper-Schnittstelle nicht im Geringsten implementiert.

public class RundZylinder {
    // Felder
    public int hoehe, radius;
    // Konstruktor
    public RundZylinder(int hoehe, int radius) {
        this.radius = radius;
        this.hoehe = hoehe;
    }
    // Eigenschaften
    public double flaeche {
        get {
            return 2 * Math.PI * radius * hoehe + 2 * Math.PI * Math.Pow(radius, radius);
        }
    }
}
Bereits fertige, aber für IKoerper unpassende Klasse

Statt nun eine neue KreisZylinder-Klasse zu erstellen, welche den Quelltext aus der anderen Klasse – sofern er überhaupt vorliegt – kopiert und von Grund auf neu implementiert, bedient man sich einer Adapter-Klasse, welche exakt die Schnittstelle IKoerper implementiert und genau ein Objekt vom Typ RundZyliner kapselt. Alle Anfragen bzgl. Eigenschaften und Methoden, welche die Schnittstelle voraussetzen und der Programmierung als Arbeitsauftrag liefern, werden nun genau auf dieses Objekt abgebildet. Dies ist im nachfolgenden Quelltext insbesondere sehr schön für die Methode errechneFlaeche zu sehen, die letztendlich einfach nur den Wert der Eigenschaft aus dem RundZylinder-Objekt, welches in dieser Klasse erstellt wird, zurückliefert.

public class KreisZylinder : IKoerper {
    // Felder
    private RundZylinder form;
    // Eigenschaften
    public int laenge {
        get { return 2 * form.radius; }
    }
    public int breite {
        get { return 2 * form.radius; }
    }
    public int hoehe {
        get { return form.hoehe; }
    }
    // Konstruktor
    public KreisZylinder (int hoehe, int radius) {
        form = new RundZylinder(hoehe, radius);
    }
    // Methoden
    public double errechneFlaeche(){
        return Math.Round(form.flaeche,2);
    }
}
Umhüllende Adapter-Klasse für fertige Lösung

Die ganze Arbeit macht natürlich nur Sinn, wenn ich das dadurch nutzbare polymorphe Verhalten, welches durch die Schnittstelle aufgebaut wird, auch tatsächlich nutze. In der FormFabrik-Klasse, die hier als Klientenklasse auftritt und zufällig unterschiedliche geometrische Objekte erzeugt, lässt sich nun ganz einfach auch ein Kreiszylinder mit der bereits fertigen Implementierung aus der RundZylinder-Klasse aufrufen. Da man ausschließlich mit dem auf Basis von IKoerper erstellten Adapter arbeitet und nicht mit der originalen Klasse, kann man diesen Adapter zurückliefern, der das eigentlich unpassende RundZylinder-Objekt umhüllt und die öffentlichen Komponenten auf dieses gekapselte Objekt anwendet.

public class FormFabrik  {
  public IKoerper erzeugeForm() {
     // .. Zufallszahlenerzeugung
     else if (zahl >= 2 & zahl <5){
        return new KreisZylinder(3, 2);
     }
    // else...
  }
}
Klientenklasse, die nur IKoerper verarbeiten kann

Zum Schluss folgt noch das UML-Diagramm, das für dieses Beispiel entsteht und für das Muster sehr charakteristisch ist. Innerhalb des Adapters liegt eine Komposition vor, da es die Entstehung und Zerstörung eines anderen Objektes, welches es für die Schnittstelle adaptiert / anpasst, kontrolliert. Zusätzlich wird das adaptierte Objekt automatisch zerstört, wenn das Adapter-Objekt zerstört wird. Der Adapter fügt sich passend in die Gruppe vorhandener Klassen ein, die alle jeweils eine bestimmte Schnittstelle implementieren. Daraus folgt, dass also auch eine Klientenklasse, die sich hier auf die Schnittstelle bezieht, ebenfalls mit dem adaptierten Objekt unter Verwendung eines Adapters arbeiten kann.

Adapter-Muster

Adapter-Muster

    Comelio GmbH C#.NET - Adapter-Muster - Design Patterns / Entwurfsmuster C#.NET Microsoft Programmierung Syntax Entwurfsmuster Anleitung .NET Tutorial Code Beispiel -Comelio GmbH C#.NET - Adapter-Muster - Design Patterns / Entwurfsmuster C#.NET Microsoft Programmierung Syntax Entwurfsmuster Anleitung .NET Tutorial Code Beispiel -Comelio GmbH C#.NET - Adapter-Muster - Design Patterns / Entwurfsmuster C#.NET Microsoft Programmierung Syntax Entwurfsmuster Anleitung .NET Tutorial Code Beispiel -Comelio GmbH C#.NET - Adapter-Muster - Design Patterns / Entwurfsmuster C#.NET Microsoft Programmierung Syntax Entwurfsmuster Anleitung .NET Tutorial Code Beispiel -Comelio GmbH C#.NET - Adapter-Muster - Design Patterns / Entwurfsmuster C#.NET Microsoft Programmierung Syntax Entwurfsmuster Anleitung .NET Tutorial Code Beispiel -Comelio GmbH C#.NET - Adapter-Muster - Design Patterns / Entwurfsmuster C#.NET Microsoft Programmierung Syntax Entwurfsmuster Anleitung .NET Tutorial Code Beispiel -Comelio GmbH C#.NET - Adapter-Muster - Design Patterns / Entwurfsmuster C#.NET Microsoft Programmierung Syntax Entwurfsmuster Anleitung .NET Tutorial Code Beispiel -Comelio GmbH C#.NET - Adapter-Muster - Design Patterns / Entwurfsmuster C#.NET Microsoft Programmierung Syntax Entwurfsmuster Anleitung .NET Tutorial Code Beispiel -Comelio GmbH C#.NET - Adapter-Muster - Design Patterns / Entwurfsmuster C#.NET Microsoft Programmierung Syntax Entwurfsmuster Anleitung .NET Tutorial Code Beispiel -