## 4.6 Hat-ein(e)-Beziehungen Eine Ist-ein(e)-Beziehung wird durch eine Vererbungsbeziehung geprägt. Ein Objekt vom Typ einer abgeleiteten Klasse ist gleichzeitig auch immer vom Typ der Basisklasse. Die daraus resultierenden Konsequenzen haben wir in den letzten Abschnitten ausgiebig diskutiert. Die ziemlich abstrakt anmutende Denkweise der Vererbung lässt sich aber recht gut auf die reale Welt abbilden. Allerdings können wir damit nicht alle Forderungen abdecken. Stellen Sie sich beispielsweise nur vor, Sie müssten die Klasse eines Motorflugzeugs modellieren. Die Klasse Flugzeug könnte die Zustandsdaten bereitstellen (beispielsweise die Spannweite), die in einem Konstruktor initialisiert werden, z. B. so:
    public class Flugzeug {
      private double spannweite;
      public Flugzeug(double Spannweite) {
        spannweite = Spannweite;
      }
      // weiterer Klassencode
    }
Da es sich um die Beschreibung eines Motorflugzeugs handelt, sollten wir auch noch die Klasse Triebwerk bereitstellen. Die Daten eines Triebwerks werden im Konstruktor initialisiert, außerdem enthält der Entwurf zwei Methoden, mit denen das Triebwerk angelassen und abgeschaltet werden kann.
    public class Triebwerk {
      private int leistung;
      private double gewicht;
      public Triebwerk(int leistung, double gewicht) {
        this.leistung = leistung;
        this.gewicht = gewicht;
      }
      // Triebwerk starten
      public void StartEngine() {
        Console.WriteLine("Das Triebwerk wird gestartet");
      }
      // Triebwerk ausschalten
      public void StopEngine() {
        Console.WriteLine("Das Triebwerk wird abgeschaltet");
      }
    }
In der realen Welt stehen Objekte dieser beiden Klassen miteinander in einer Beziehung, die nicht durch eine Vererbungslinie abgebildet werden kann. Denken Sie daran, dass die Implementierungsvererbung eine Beziehung zwischen Typen beschreibt, die als Ist-ein(e)-Beziehung bezeichnet wird. Dass ein Flugzeug aber kein Triebwerk ist oder umgekehrt ein Triebwerk kein Flugzeug, leuchtet ein. Um die beiden miteinander in einer unzertrennlichen Beziehung stehenden Typen Flugzeug und Triebwerk zu beschreiben, müsste man sagen, dass ein Flugzeug ein Triebwerk hat. Der vorliegende Sachverhalt einer Hat-ein(e)-Beziehung wird auch im objektorientierten Sprachgebrauch zum Ausdruck gebracht. Ein Flugzeug hat ein Triebwerk, folgerichtig muss die Klassendefinition Flugzeug eine Eigenschaft vom Typ Triebwerk haben. Die Klasse Flugzeug kann mit dieser Überlegung folgendermaßen verbessert werden:
    public class Flugzeug {
      private Triebwerk motor;
      ...
    }
In der übergeordneten Klasse Flugzeug ist das untergeordnete Objekt vom Typ Triebwerk als private deklariert. Diese Kapselung entspricht den Paradigmen der objektorientierten Programmierung, wirft jedoch auch sofort die Frage auf, wie ein Objekt vom Typ Triebwerk instanziiert und später gestartet bzw. ausgeschaltet werden kann. Um bei der Instanziierung eines Flugzeugobjekts sofort eine gültige Referenz auf ein Triebwerksobjekt zu erhalten, eignet sich der Konstruktor der Klasse Flugzeug, in dem die Klasse Triebwerk instanziiert und mit den notwendigen Initialisierungsdaten versorgt wird:
    public class Flugzeug {
      private Triebwerk motor;
      ...
      // aktualisierter Konstruktor der Klasse Flugzeug
      public Flugzeug(double spannweite, int leistung,
                      double gewicht) {
        this.spannweite = spannweite;
        motor = new Triebwerk(leistung, gewicht);
      }
      // weiterer Klassencode
    }
Nun beschreibt ein Objekt vom Typ Flugzeug ein ganz bestimmtes Objekt vom Typ Triebwerk – das Triebwerk ist dem Flugzeug eindeutig zugeordnet. Was bleibt, ist das Starten und Ausschalten des Triebwerks. Dazu bieten sich zwei Alternativen an: Die Definition einer Eigenschaft, die die Referenz auf das Triebwerk zurückliefert. Auf dieser Referenz können anschließend die triebwerksspezifischen Methoden StartEngine und StopEngine aufgerufen werden. Die Definition einer Methode in der Klasse Flugzeug, die den Methodenaufruf an das untergeordnete Triebwerksobjekt weiterleitet. #### Weiterleitung einer internen Objektreferenz Sehen wir uns zuerst die Realisierung mittels einer Eigenschaftsmethode an, die die Referenz auf das Triebwerksobjekt an den Aufrufer weiterleitet. Auf den set-Accessor kann verzichtet werden, weil das Triebwerksobjekt bereits im Konstruktor erzeugt wird:
    public class Flugzeug {
      private Triebwerk motor;
      public Triebwerk Motor {
        get {return motor;}
      }
      // weiterer Klassencode
    }
Sehen wir uns den Programmcode zusammengefasst an:
    // ------------------------------------------------------------------
    // Beispiel: ...\Kapitel 4\HatEineBeziehung_1
    // ------------------------------------------------------------------
    class Program {
      static void Main(string[] args) {
        Flugzeug myCessna = new Flugzeug(8, 150, 300);
        myCessna.Motor.StartEngine();
        myCessna.Motor.StopEngine();
        Console.ReadLine();
      }
    }
    public class Flugzeug {
      private double spannweite;
      private Triebwerk motor;
      public Flugzeug(double spannweite, int leistung, double gewicht) {
        this.spannweite = spannweite;
        motor = new Triebwerk(leistung, gewicht);
      }
      public Triebwerk Motor {
        get {return motor;}
      }
    }
    public class Triebwerk {
      private int leistung;
      private double gewicht;
      public Triebwerk(int leistung, double gewicht) {
        this.leistung = leistung;
        this.gewicht = gewicht;
      }
      public void StartEngine() {
        Console.WriteLine("Das Triebwerk wird gestartet");
      }
      public void StopEngine() {
        Console.WriteLine("Das Triebwerk wird abgeschaltet");
      }
    }
Der Benutzer besorgt sich nach der Instanziierung der Klasse Flugzeug die Referenz auf das interne Triebwerksobjekt und kann darauf die beiden Methoden StartEngine und StopEngine aufrufen:
    Flugzeug myCessna = new Flugzeug(8, 150, 300);
    myCessna.Motor.StartEngine();
    ...
    myCessna.Motor.StopEngine();
Der Teilausdruck
    myCessna.Motor
liefert die Referenz auf das Triebwerk, über die mit der üblichen Punktnotation auf alle Klassenmitglieder des internen Objekts zugegriffen werden kann. Festzustellen ist, dass dem Aufrufer nicht verborgen bleibt, dass ein zweites, internes Objekt der übergeordneten Klasse seine Dienste bereitstellt. #### Verbergen des internen Objekts Betrachten wir nun die zweite Alternative. In der Klasse Flugzeug sind dazu zwei Methoden definiert: die erste, um das Triebwerk einzuschalten, und die zweite, um es wieder auszuschalten. Der Aufruf wird in den Methoden an das interne Triebwerksobjekt weitergeleitet.
    public class Flugzeug {
      private Triebwerk motor;
      ...
      public void StartMotor() {
        motor.StartEngine();
      }
      public void StopMotor() {
        motor.StopEngine();
      }
    }
Der Aufruf einer der beiden Instanzmethoden StartMotor oder StopMotor des Flugzeug-Objekts bewirkt, dass das Triebwerk das gewünschte Verhalten zeigt: Es wird angelassen oder abgeschaltet. Anders als bei der Weiterleitung der internen Objektreferenz bemerkt der Aufrufer nicht, dass das Flugzeug-Objekt sich hinterlistig der Funktionalität einer zweiten Klasse bedient. Wenn wir voraussetzen, dass die Codeimplementierung der beiden Methoden in der untergeordneten Klasse Triebwerk möglicherweise sehr komplex ist, gaukelt diese Lösung dem Aufrufer Intelligenz vor und verbirgt dabei den tatsächlichen Dienstanbieter – ganz im Gegensatz zu der zuerst vorgestellten Variante. Fassen wir an dieser Stelle den Programmcode wieder zusammen:
    // ------------------------------------------------------------------
    // Beispiel: ...\Kapitel 4\HatEineBeziehung_2
    // ------------------------------------------------------------------
    class Program {
      static void Main(string[] args) {
        Flugzeug myPiper = new Flugzeug(9, 180, 250);
        myPiper.StartMotor();
        myPiper.StopMotor();
        Console.ReadLine();
      }
    }
    // ----------- Klasse Flugzeug -----------
    class Flugzeug {
      private double spannweite;
      private Triebwerk motor;
      public Flugzeug(double Spannweite, int Leistung,
                      double Gewicht) {
        spannweite = Spannweite;
        motor = new Triebwerk(Leistung, Gewicht);
      }
      public void StartMotor() {
        motor.StartEngine();
      }
      public void StopMotor() {
        motor.StopEngine();
      }
    }
    // ---------- Klasse Triebwerk -----------
    public class Triebwerk {
      private int leistung;
      private double gewicht;
      public Triebwerk(int Leistung, double Gewicht) {
        leistung = Leistung;
        gewicht = Gewicht;
      }
      public void StartEngine() {
        Console.WriteLine("Der Motor wird gestartet");
      }
      public void StopEngine() {
        Console.WriteLine("Der Motor wird abgeschaltet");
      }
    }
### 4.6.1 Innere Klassen (Nested Classes) Es gibt noch eine andere Möglichkeit, Hat-ein(e)-Beziehungen zu realisieren. Dazu wird im Gültigkeitsbereich einer Klasse eine weitere Klasse definiert:
    public class ClassA {
      public class ClassB {
        // Code der Klasse ClassB
      }
      // Code der Klasse ClassA
    }
Eine Klasse, die innerhalb einer anderen Klasse definiert ist, wird als innere Klasse bezeichnet. Im Codefragment ist das die Definition der Klasse ClassB in ClassA. Die Verwendung innerer Klassen ist eine bequeme Möglichkeit zur Bereitstellung untergeordneter Objekte und wird benutzt, wenn ein Typ einem anderen Typ logisch zugeordnet werden kann. Rufen Sie sich noch einmal das Beispiel des Flugzeugs und des Triebwerks in Erinnerung, deren Klassen wir weiter oben folgendermaßen definiert hatten:
    class Flugzeug {/*...*/}
    class Triebwerk {/*...*/}
Ein Triebwerk ist eine Bauteilkomponente eines Flugzeugs. Wenn kein Zwang dazu besteht, ein Triebwerk auch als separates Objekt einer Betrachtung zu unterziehen, wäre es überlegenswert, die Definition Triebwerk in der Definition Flugzeug einzuschließen:
    public class Flugzeug {
      public class Triebwerk {
        ...
      }
    }
Ein Objekt vom Typ Triebwerk ist jetzt abhängig von einem Objekt des Typs Flugzeug und kann nur im Kontext der äußeren Klasse, hier also von Flugzeug, benutzt werden. Ist die innere Klasse als public deklariert, muss bei der Instanziierung immer der Typ der äußeren Klasse angegeben werden.
    Flugzeug.Triebwerk turbine = new Flugzeug.Triebwerk(545, 320);
Die eindeutige Zugehörigkeit eines Triebwerk-Objekts zu einem Flugzeug zeigt sich erst, wenn das Flugzeug-Objekt ein ihm zugeordnetes Triebwerk hat. Dazu wird im Konstruktor der äußeren Klasse die innere Klasse instanziiert und die Referenz in einer gekapselten Variablen vorgehalten.
    public class Flugzeug {
      private Triebwerk turbine;
      public Flugzeug() {
        turbine = new Triebwerk();
      }
      public class Triebwerk {/*...*/}
    }
Festhalten können wir, dass sich im Vergleich zu zwei separaten Klassendefinitionen, wie wir sie anfangs hatten, nicht viel geändert hat. Interessant wird es, wenn die innere Klasse als private deklariert wird:
    public class Flugzeug {
      ...
      private class Triebwerk {/*...*/}
    }
Die Klasse Triebwerk ist nun ein eindeutig einem Flugzeug-Objekt zugeordnetes Element. Kein anderer Code, außer dem Code in der äußeren Klasse, hat Zugriff auf den inneren Typ. Doch wie kann ein Aufrufer ein Triebwerk starten, wenn der Typ Triebwerk für ihn völlig unsichtbar bleibt und er deshalb nicht die klassenspezifischen Methoden aufrufen kann? Die Lösung führt wieder über Methoden, die in der äußeren Klasse Flugzeug definiert sind:
    public class Flugzeug {
      private Triebwerk motor = new Triebwerk(200, 56);
      ...
      public void TurbineStarten() {
        motor.StartEngine();
      }
      // innere Klasse
      private class Triebwerk {
        ...
         public void StartEngine() {
           Console.WriteLine("Die Turbine wird gestartet");
         }
      }
    }
Weil die Klasse Triebwerk jetzt als private deklariert ist, hat sie eine Sichtbarkeit wie jede andere private Entität der äußeren Flugzeug-Klasse. Ein Flugzeug-Objekt kann die innere, private Klasse instanziieren. Der resultierende Verweis wird in der Methode TurbineStarten zum Aufruf der Methode StartEngine benutzt. Obwohl der Aufrufer nichts von der Existenz der Klasse Triebwerk weiß, wird er Nutzen aus dieser Klasse ziehen können und die Reaktion auf den Aufruf zu spüren bekommen – und sei es nur die Ausgabe im Konsolenfenster. #### Gegenseitige Abhängigkeit von äußerer und innerer Klasse Wir wollen jetzt unsere Überlegungen hinsichtlich der Abhängigkeit der beiden Klassen Flugzeug und Triebwerk auf die Spitze treiben. Wenn wir es ganz streng sehen, müssen wir feststellen, dass ein Flugzeug ein Triebwerk besitzt und ein Triebwerk auch in einem ganz bestimmten Flugzeug eingebaut ist. Deklarieren wir die innere Klasse Triebwerk als public und instanziieren sie mit
    Flugzeug.Triebwerk turbine = new Flugzeug.Triebwerk(545, 320);
fehlt dem Triebwerk die Information darüber, in welchem Flugzeug es eingebaut ist. Um eine eindeutige Zuordnung zu gewährleisten, übergeben wir dem Konstruktoraufruf des Triebwerk-Objekts die Referenz auf das Flugzeug-Objekt, dem das Triebwerk zugeordnet wird. Diese wird in einem privaten Feld flugzeug der Klasse Triebwerk gespeichert. Sehen wir uns nun die Klassendefinition von Flugzeug an, die sich auf das Wesentlichste beschränkt. Damit wir uns später im Testcode vom Erfolg überzeugen können, wird ein Flugzeug durch einen Namen beschrieben, der dem Konstruktor der Klasse Flugzeug bei der Instanziierung übergeben wird. Außerdem wird die Eigenschaft Motor mit der Rückgabe der Referenz auf das Triebwerk-Objekt angeboten, über die ein Benutzer Zugriff auf die Methoden des Triebwerks hat.
    // -------------------------------------------------------------
    // Beispiel: ...Kapitel 4\InnereKlassen
    // -------------------------------------------------------------
    public class Flugzeug {
      private Triebwerk motor;
      private string name;
      public Flugzeug(string bezeichnung)   {
        motor = new Triebwerk(this);
        this.name = bezeichnung;
      }
      public Triebwerk Motor {
        get {return this.motor;}
      }
      public void Starten() {
        Console.WriteLine("Das Flugzeug {0} startet", this.name);
      }
      // ------------ innere Klasse Triebwerk ---------------
      public class Triebwerk {
        private Flugzeug flugzeug;
        public Triebwerk(Flugzeug flg) {
          this.flugzeug = flg;
          this.flugzeug.motor = this;
        }
        public void StartEngine() {
          Console.WriteLine("Das Triebwerk wird gestartet");
        }
      }
    }
Wir können nun die Klasse Flugzeug instanziieren und die Eigenschaft Motor aufrufen, die ihrerseits die Referenz auf das dem Flugzeug zugeordnete Triebwerk liefert. Damit können wir das Triebwerk starten:
    Flugzeug flg = new Flugzeug("Piper");
    flg.Motor.StartEngine();
Wir haben auch die Möglichkeit, die innere Klasse Triebwerk zu instanziieren. Dabei müssen wir dem Konstruktor die Referenz auf ein konkretes Flugzeug-Objekt übergeben:
    Flugzeug flg = new Flugzeug("Piper");
    Flugzeug.Triebwerk trb = new Flugzeug.Triebwerk(flg);
Grundsätzlich birgt dieser Aufruf die Gefahr der Inkonsistenz, denn wir erzeugen ein neues Triebwerk auf Basis des konkreten Flugzeugs flg. Dieses Flugzeug-Objekt ist aber bereits im Besitz eines Triebwerks, das im Konstruktor erzeugt worden ist und dessen Referenz im Feld motor vorgehalten wird. Wir müssen dem Flugzeug-Objekt mitteilen, dass das erste Triebwerk »ausgetauscht« und durch ein neues ersetzt wird. Um dem Flugzeug die Existenz des neuen Triebwerks mitzuteilen, enthält der Konstruktor der Klasse Triebwerk folgende Anweisung:
    this.flugzeug.motor = this;
Nun ist der Kreis vollständig geschlossen. Jedes Triebwerk ist unzweifelhaft einem bestimmten Flugzeug zugeordnet, und jedes Flugzeug hat auch nur ein bestimmtes Triebwerk. #### Zugriffsmodifizierer einer inneren Klasse Wie Sie oben gesehen haben, unterscheidet sich eine öffentlich (als public oder als internal) deklarierte innere Klasse nicht wesentlich von einer separaten Klassendefinition. Ein Benutzer sieht die innere Klasse und kann sie instanziieren. Das Konzept der verschachtelten Klassen, nämlich die konkrete Zugehörigkeit zu einem Objekt der umschließenden Klasse, wird dadurch aufgeweicht. Ganz anders verhält sich eine als private deklarierte innere Klasse. Die Sichtbarkeit ist nur auf das umschließende äußere Objekt begrenzt, und die Bindung ist eindeutig und kann nicht aufgebrochen werden. Erst jetzt kann der Verbund zwischen dem vom Aufrufer erkennbaren Objekt und seinem zugeordneten Teilobjekt die konzeptuellen Stärken voll ausspielen.