Skip to content

5. Spring IoC in der Praxis

Wir werden nun anhand von Beispielen die praktische Umsetzung des zuvor Gesehenen behandeln.

5.1. Beispiel 1

Die Klasse [Personne.vb] sieht wie folgt aus:

Namespace istia.st.springioc.demos
    Public Class Personne

         ' private Felder
        Private _nom As String
        Private _age As Integer

         ' Standardkonstruktor
        Public Sub New()
        End Sub

         ' mit den privaten Feldern verknüpfte Eigenschaften
        Public Property nom() As String
            Get
                Return _nom
            End Get
            Set(ByVal Value As String)
                _nom = Value
            End Set
        End Property

        Public Property age() As Integer
            Get
                Return _age
            End Get
            Set(ByVal Value As Integer)
                _age = Value
            End Set
        End Property

         ' Identitätszeichenfolge
        Public Overrides Function tostring() As String
            Return String.Format("[{0},{1}]", nom, age)
        End Function

         ' init-Methode
        Public Sub init()
            Console.WriteLine("init personne {0}", Me.ToString)
        End Sub

         ' close-Methode
        Public Sub close()
            Console.WriteLine("destroy personne {0}", Me.ToString)
        End Sub

    End Class
End Namespace

Die Klasse enthält:

  • zwei private Felder „name“ und „age“, auf die über Eigenschaften zugegriffen werden kann
  • eine Methode „toString“, um den Wert des Objekts „[Personne]“ in Form einer Zeichenkette abzurufen
  • eine Methode „init“, die von Spring bei der Erstellung des Objekts aufgerufen wird, eine Methode „close“, die bei der Löschung des Objekts aufgerufen wird

Um Objekte vom Typ [Personne] zu erstellen, verwenden wir die folgende Spring-Datei [spring-config-1.xml]:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">

<objects>
    <object id="personne1" type="istia.st.springioc.demos.Personne, demo1" init-method="init"
        destroy-method="close">
        <property name="nom">
            <value>Simon</value>
        </property>
        <property name="age">
            <value>40</value>
        </property>
    </object>
    <object id="personne2" type="istia.st.springioc.demos.Personne, demo1" init-method="init"
        destroy-method="close">
        <property name="nom">
            <value>Brigitte</value>
        </property>
        <property name="age">
            <value>20</value>
        </property>
    </object>
</objects>

Diese Datei

  • definiert zwei Schlüsselobjekte mit den Bezeichnungen „Person1“ und „Person2“ vom Typ [Personne]
  • initialisiert die Eigenschaften [nom, age] jeder Person
  • sie definiert die Methoden, die beim anfänglichen Aufbau des Objekts [init-method] und beim Abbau des Objekts [destroy-method] aufgerufen werden sollen

Für unsere Tests verwenden wir Testklassen vom Typ NUnit. Die erste sieht wie folgt aus:

Imports System
Imports Spring.Objects.Factory.Xml
Imports System.IO
Imports NUnit.Framework
Imports istia.st.springioc.demos

Namespace istia.st.springioc.tests

    <TestFixture()> _
    Public Class NunitTestSpringIocDemo1
         ' das zu testende Objekt
        Private factory As XmlObjectFactory

        <SetUp()> _
        Public Sub init()
             ' Es wird eine Instanz der Factory erstellt
            factory = New XmlObjectFactory(New FileStream("spring-config-1.xml", FileMode.Open))
             ' Protokoll
            Console.WriteLine("setup test")
        End Sub

        <Test()> _
        Public Sub demo()
             ' Abruf der Objekte [Personne] aus der Spring-Datei anhand ihres Schlüssels
            Dim personne1 As Personne = CType(factory.GetObject("personne1"), Personne)
            Console.WriteLine("personne1=" + personne1.ToString())
            Dim personne2 As Personne = CType(factory.GetObject("personne2"), Personne)
            Console.WriteLine("personne2=" + personne2.ToString())
            personne2 = CType(factory.GetObject("personne2"), Personne)
            Console.WriteLine("personne2=" + personne2.ToString())
        End Sub

        <TearDown()> _
        Public Sub destroy()
             ' Die Singletons werden zerstört
            factory.Dispose()
             ' Die Factory-Ressource wird freigegeben
            factory = Nothing
             ' Weiterverfolgung
            Console.WriteLine("teardown test")
        End Sub

    End Class
End Namespace

Anmerkungen:

  • Um die in der Datei [spring-config-1.xml] definierten Objekte abzurufen, verwenden wir ein Objekt vom Typ [XmlObjectFactory]. Es gibt weitere „Factory“-Typen, mit denen auf die Singletons der Konfigurationsdatei zugegriffen werden kann. Das Objekt [XmlObjectFactory] wird in der Attributmethode [SetUp] der Testklasse abgerufen und in einer privaten Variablen gespeichert. Zur Erinnerung: Die Methode mit dem Attribut <Setup()> wird vor jedem Test ausgeführt.
  • Die Datei „[spring-config-1.xml]“ wird im Ordner „[bin]“ der Anwendung abgelegt
  • Spring kann Konfigurationsdateien in verschiedenen Formaten verwenden. Mit dem Objekt [XmlObjectFactory] lässt sich eine Konfigurationsdatei im Format XML analysieren.
  • Die Auswertung einer Spring-Datei liefert ein Objekt vom Typ [XmlObjectFactory], in diesem Fall das Factory-Objekt. Mit diesem Objekt lässt sich ein durch den Schlüssel C identifiziertes Singleton über factory.getObject(C) abrufen.
  • Die Methode [demo] fragt den Wert der Singletons mit den Schlüsseln „personne1“ und „personne2“ ab und gibt ihn aus.

Die Struktur des Visual Studio-Projekts ist wie folgt:

Image

Anmerkungen:

  • Das Projekt VS heißt [demo1]
  • Der Ordner [istia] enthält den Quellcode. Der kompilierte Code wird in den Ordner [bin] im Verzeichnis DLL verschoben. [demo1.dll]:

Image

  • Die Datei [spring-config-1.xml] befindet sich im Ordner [bin] des Projekts.
  • Der Ordner „[bin]“ enthält die für die Anwendung erforderlichen Dateien:
    • Spring.Core.dll, Spring.Core.xml für die Spring-Klassen
    • log4net.dll für die Spring-Protokolle
    • demo1.dll, bei dem es sich um die durch die Projektgenerierung erstellte Datei DLL handelt

Die durch die Projektgenerierung erzeugte Datei „DLL“ („[demo1.dll]“) wird in das grafische Testtool „[Nunit-Gui 2.2]“ geladen. Dieses zeigt automatisch die in der Datei „DLL“ enthaltenen NUnit-Klassen an:

Image

Die Ausführung der Methode [demo] des Tests NUnit liefert die oben angegebenen und unten aufgeführten Ergebnisse:

***** istia.st.springioc.tests.NunitTestSpringIocDemo1.demo
setup test
init personne [Simon,40]
personne1=[Simon,40]
init personne [Brigitte,20]
personne2=[Brigitte,20]
personne2=[Brigitte,20]
destroy personne [Simon,40]
destroy personne [Brigitte,20]
teardown test

Anmerkungen:

  • Zeile 2: Der Test beginnt mit der Ausführung der Attributmethode <Setup()>
  • Zeile 3: Die Operation
            Dim personne1 As Personne = CType(factory.GetObject("personne1"), Personne)

hat die Erstellung des Beans [personne1] erzwungen. Da in der Definition des Singletons [personne1] versehentlich [init-method="init"] geschrieben wurde, wurde die Methode [init] des erstellten Objekts [Personne] ausgeführt. Die entsprechende Meldung wird angezeigt.

init personne [Simon,40]
  • Zeile 4: Die Operation
            Console.WriteLine("personne1=" + personne1.ToString())

hat den Wert des angelegten Objekts [Personne] angezeigt.

personne1=[Simon,40]
  • Zeilen 5–6: Das gleiche Phänomen wiederholt sich für den Schlüssel-Bean [personne2].
init personne [Brigitte,20]
personne2=[Brigitte,20]
  • Zeile 7: der letzte Vorgang
personne2 = CType(factory.GetObject("personne2"), Personne)
Console.WriteLine("personne2=" + personne2.ToString())

hat nur eine Anzeigezeile ergeben:

personne2=[Brigitte,20]

Sie hat also nicht zur Erstellung eines neuen Objekts vom Typ [Personne] geführt. Wäre dies der Fall gewesen, wäre die Methode [init] angezeigt worden, was hier jedoch nicht der Fall ist. Das ist das Prinzip des Singletons. Spring erstellt standardmäßig nur ein einziges Exemplar der Beans aus seiner Konfigurationsdatei. Es handelt sich um einen Objektreferenzdienst. Wenn man ihn nach der Referenz eines noch nicht erstellten Objekts fragt, erstellt er dieses und gibt eine Referenz darauf zurück. Wenn das Objekt bereits erstellt wurde, gibt Spring lediglich eine Referenz darauf zurück.

  • Zeilen 8–10: Die Attributmethode <TearDown()> wird ausgeführt (Zeile 10). Darin wird die Operation
             ' Die Singletons werden zerstört
            factory.Dispose()

die Zerstörung der von Spring erstellten Singletons aus. Dies führt bei jedem von ihnen zur Ausführung ihrer Methode [close], da in der Konfigurationsdatei für jeden von ihnen „destroy-method=close“ angegeben wurde. Dies geht aus den folgenden Ausgaben hervor:

destroy personne [Simon,40]
destroy personne [Brigitte,20]

Da wir nun die Grundlagen einer Spring-Konfiguration verstanden haben, werden wir im weiteren Verlauf etwas schneller vorankommen.

5.2. Beispiel 2

Betrachten wir die folgende neue Klasse [Voiture]:

Imports istia.st.springioc.demos

Namespace istia.st.springioc.demos

    Public Class Voiture
         ' private Felder
        Private _marque As String
        Private _type As String
        Private _propriétaire As Personne

         ' öffentliche Eigenschaften
        Public Property marque() As String
            Get
                Return _marque
            End Get
            Set(ByVal Value As String)
                _marque = Value
            End Set
        End Property

        Public Property type() As String
            Get
                Return _type
            End Get
            Set(ByVal Value As String)
                _type = Value
            End Set
        End Property

        Public Property propriétaire() As Personne
            Get
                Return _propriétaire
            End Get
            Set(ByVal Value As Personne)
                _propriétaire = Value
            End Set
        End Property

         ' Standardkonstruktor
        Public Sub New()

        End Sub

         ' Konstruktor mit drei Parametern
        Public Sub New(ByVal marque As String, ByVal type As String, ByVal propriétaire As Personne)
             ' Die privaten Felder werden über ihre zugehörigen Eigenschaften initialisiert
            With Me
                .marque = marque
                .type = type
                .propriétaire = propriétaire
            End With
        End Sub

         ' Identitätszeichenfolge des Objekts „Auto“
        Public Overrides Function tostring() As String
            Return String.Format("[{0},{1},{2}]", marque, type, propriétaire.ToString)
        End Function

         ' Methoden „init“ und „destroy“
        Public Sub init()
            Console.WriteLine("init voiture {0}", Me.ToString)
        End Sub

        Public Sub destroy()
            Console.WriteLine("destroy voiture {0}", Me.ToString)
        End Sub

    End Class
End Namespace

Die Klasse enthält:

  • drei private Felder: _type, _marque und _propriétaire. Diese Felder können über öffentliche Eigenschaften initialisiert und ausgelesen werden. Sie können auch mithilfe des Konstruktors „Auto(String, String, Person)“ initialisiert werden. Die Klasse verfügt außerdem über einen Konstruktor ohne Argumente, mit dem zunächst ein nicht initialisiertes Objekt vom Typ [Voiture] erstellt und anschließend über seine öffentlichen Eigenschaften initialisiert werden kann.
  • eine Methode toString, um den Wert des Objekts [Voiture] in Form einer Zeichenkette abzurufen
  • eine Methode „init“, die von Spring unmittelbar nach der Erstellung des Objekts aufgerufen wird, eine Methode „destroy“, die bei der Löschung des Objekts aufgerufen wird

Um Objekte vom Typ [Voiture] zu erstellen, verwenden wir die folgende Spring-Datei [spring-config-2.xml]:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">
<objects>
     <!-- Personen -->
    <object id="personne1" type="istia.st.springioc.demos.Personne, demo1" init-method="init"
        destroy-method="close">
        <property name="nom">
            <value>Simon</value>
        </property>
        <property name="age">
            <value>40</value>
        </property>
    </object>
    <object id="personne2" type="istia.st.springioc.demos.Personne, demo1" init-method="init"
        destroy-method="close">
        <property name="nom">
            <value>Brigitte</value>
        </property>
        <property name="age">
            <value>20</value>
        </property>
    </object>
     <!-- ein Auto -->
    <object id="voiture1" type="istia.st.springioc.demos.Voiture, demo1" init-method="init"
        destroy-method="destroy">
        <constructor-arg index="0">
            <value>Peugeot</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>307</value>
        </constructor-arg>
        <constructor-arg index="2">
            <ref object="personne2"/>
        </constructor-arg>
    </object>
</objects>

Diese Datei ergänzt die vorherigen Definitionen um ein Schlüsselobjekt „Auto1“ vom Typ [Voiture]. Um dieses Objekt zu initialisieren, hätte man Folgendes schreiben können:

    <object id="voiture1" type="istia.st.springioc.demos.Voiture, demo1" init-method="init"
        destroy-method="destroy">
        <constructor-arg index="0">
            <value>Peugeot</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>307</value>
        </constructor-arg>
        <constructor-arg index="2">
            <ref object="personne2"/>
        </constructor-arg>
    </object>

Anstatt diese bereits vorgestellte Methode zu wählen, haben wir uns hier dafür entschieden, den Konstruktor „Auto(String, String, Person)“ der Klasse zu verwenden. Außerdem definiert das Singleton [voiture1] die Methode, die bei der anfänglichen Erstellung des Objekts [init-method] aufgerufen werden soll, sowie die Methode, die bei der Löschung des Objekts [destroy-method] aufgerufen werden soll.

Für unsere Tests verwenden wir die folgende Testklasse NUnit [NunitTestSpringIocDemo2]:

Imports System
Imports Spring.Objects.Factory.Xml
Imports System.IO
Imports NUnit.Framework
Imports istia.st.springioc.demos

Namespace istia.st.springioc.tests

    <TestFixture()> _
    Public Class NunitTestSpringIocDemo2
         ' die Singleton-Factory
        Private factory As XmlObjectFactory

        <SetUp()> _
        Public Sub init()
             ' Man erstellt eine Instanz der Factory
            factory = New XmlObjectFactory(New FileStream("spring-config-2.xml", FileMode.Open))
             ' Protokoll
            Console.WriteLine("setup test")
        End Sub

        <TearDown()> _
    Public Sub destroy()
             ' die Singletons werden zerstört
            factory.Dispose()
             ' Die Factory wird freigegeben
            factory = Nothing
             ' Nachverfolgung
            Console.WriteLine("teardown test")
        End Sub

        <Test()> _
        Public Sub demo2()
             ' Abruf des Singletons [voiture1]
            Dim voiture1 As Voiture = CType(factory.GetObject("voiture1"), Voiture)
            Console.WriteLine("Voiture1=[{0}]", voiture1)
        End Sub

    End Class
End Namespace

Anmerkungen:

  • Die Attributmethoden <Setup()> und <TearDown()> bleiben unverändert.
  • Die Methode [demo2] ruft eine Referenz auf das Singleton [voiture1] ab und zeigt dieses an.

Die Struktur des Visual-Studio-Projekts bleibt unverändert. Es sind lediglich zwei neue Klassen sowie eine Spring-Konfigurationsdatei hinzugekommen:

Image

Die Ausführung des Tests NUnit liefert folgende Ergebnisse:

Image

Lassen Sie uns die Bildschirmausgaben kommentieren:

1
2
3
4
5
6
7
8
***** istia.st.springioc.tests.NunitTestSpringIocDemo2.demo2
setup test
init personne [Brigitte,20]
init voiture [Peugeot,307,[Brigitte,20]]
Voiture1=[[Peugeot,307,[Brigitte,20]]]
destroy voiture [Peugeot,307,[Brigitte,20]]
destroy personne [Brigitte,20]
teardown test

Erläuterungen:

  • Zeile 2: Die Attributmethode [Setup] wird vor jedem Test ausgeführt, hier [demo]
  • Zeile 3: Spring beginnt mit der Erstellung des Singletons [voiture1]. Dieses hat eine Abhängigkeit vom Singleton [personne2], das noch nicht existiert. Letzteres wird daher erstellt und seine Methode [init] ausgeführt.
  • Zeile 4: Das Singleton [voiture1] kann nun erstellt werden. Anschließend wird seine Methode [init] ausgeführt.
  • Zeile 5: Die Methode [demo2] gibt den Wert des Singletons [voiture1] aus
  • Zeilen 6–8: Die Methode [TearDown] des Tests wird ausgeführt. Die Singletons werden zerstört, wodurch ihre Methoden [destroy] ausgeführt werden

5.3. Beispiel 3

Wir führen die folgende neue Klasse [GroupePersonnes] ein:

Imports istia.st.springioc.demos

Namespace istia.st.springioc.demos

    Public Class GroupePersonnes
         ' private Felder
        Private _membres() As Personne
        Private _groupesDeTravail As Hashtable

         ' öffentliche Eigenschaften
        Public Property membres() As Personne()
            Get
                Return _membres
            End Get
            Set(ByVal Value() As Personne)
                _membres = Value
            End Set
        End Property

        Public Property groupesDeTravail() As Hashtable
            Get
                Return _groupesDeTravail
            End Get
            Set(ByVal Value As Hashtable)
                _groupesDeTravail = Value
            End Set
        End Property

         ' Standardkonstruktor
        Public Sub New()

        End Sub

         ' Identitätszeichenfolge des Objekts GroupeDePersonnes
        Public Overrides Function tostring() As String
             ' die Liste der Gruppenmitglieder wird durchlaufen
            Dim identité As String = "[membres=("
            Dim i As Integer
            For i = 0 To membres.Length - 2
                identité += membres(i).ToString + ","
            Next
            identité += membres(i).ToString + "), groupes de travail=("
             ' Das Verzeichnis der Arbeitsgruppen wird durchlaufen
            Dim clés As IEnumerator = groupesDeTravail.Keys.GetEnumerator
            Dim clé As Object
            While clés.MoveNext
                clé = clés.Current
                identité += String.Format("[{0},{1}] ", clé, groupesDeTravail(clé))
            End While
             ' das Ergebnis wird ausgegeben
            Return identité + "]"
        End Function

         ' Methoden init-destroy
        Public Sub init()
            Console.WriteLine("init GroupeDePersonnes {0}", Me.ToString)
        End Sub

        Public Sub destroy()
            Console.WriteLine("destroy GroupeDePersonnes {0}", Me.ToString)
        End Sub

    End Class
End Namespace

Ihre beiden privaten Mitglieder sind:

_membres: ein Array mit den Mitgliedern der Gruppe

_groupesDeTravail: ein Dictionary, das eine Person einer Arbeitsgruppe zuordnet

Diese privaten Elemente werden über öffentliche Eigenschaften zugänglich gemacht. Hier soll gezeigt werden, wie Spring die Initialisierung komplexer Objekte ermöglicht, beispielsweise Objekte mit Feldern vom Typ Array oder Dictionary.

Die Spring-Konfigurationsdatei [spring-config-3.xml] sieht wie folgt aus:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">
<objects>
     <!-- Personen -->
    <object id="personne1" type="istia.st.springioc.demos.Personne, demo1" init-method="init"
        destroy-method="close">
        <property name="nom">
            <value>Simon</value>
        </property>
        <property name="age">
            <value>40</value>
        </property>
    </object>
    <object id="personne2" type="istia.st.springioc.demos.Personne, demo1" init-method="init"
        destroy-method="close">
        <property name="nom">
            <value>Brigitte</value>
        </property>
        <property name="age">
            <value>20</value>
        </property>
    </object>
     <!-- ein Auto -->
    <object id="voiture1" type="istia.st.springioc.demos.Voiture, demo1" init-method="init"
        destroy-method="destroy">
        <constructor-arg index="0">
            <value>Peugeot</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>307</value>
        </constructor-arg>
        <constructor-arg index="2">
            <ref object="personne2" />
        </constructor-arg>
    </object>
     <!-- eine Gruppe von Personen -->
    <object id="groupe1" type="istia.st.springioc.demos.GroupePersonnes" init-method="init"
        destroy-method="destroy">
        <property name="membres">
            <list>
                <ref object="personne1" />
                <ref object="personne2" />
            </list>
        </property>
        <property name="groupesDeTravail">
            <dictionary>
                <entry key="Brigitte">
                    <value>Marketing</value>
                </entry>
                <entry key="Simon">
                    <value>Ressources humaines</value>
                </entry>
            </dictionary>
        </property>
    </object>
</objects>
  1. Mit dem Tag <list> lässt sich ein Feld vom Typ „Array“ oder vom Typ IList mit verschiedenen Werten initialisieren.
  1. Mit dem Tag <dictionary> lässt sich dasselbe mit einem Feld erreichen, das die Schnittstelle IDictionary implementiert.

Für unsere Tests verwenden wir die folgende Testklasse NUnit [NunitTestSpringIocDemo3]:

Imports System
Imports Spring.Objects.Factory.Xml
Imports System.IO
Imports NUnit.Framework
Imports istia.st.springioc.demos

Namespace istia.st.springioc.tests

    <TestFixture()> _
    Public Class NunitTestSpringIocDemo3
         ' das zu testende Objekt
        Private factory As XmlObjectFactory

        <SetUp()> _
        Public Sub init()
             ' eine Factory-Instanz wird erstellt
            factory = New XmlObjectFactory(New FileStream("spring-config-3.xml", FileMode.Open))
             ' Protokoll
            Console.WriteLine("setup test")
        End Sub

        <TearDown()> _
        Public Sub destroy()
             ' die Singletons werden zerstört
            factory.Dispose()
             ' Nachverfolgung
            Console.WriteLine("teardown test")
        End Sub

        <Test()> _
    Public Sub demo3()
             ' Abruf des Singletons [groupe1]
            Dim groupe1 As GroupePersonnes = CType(factory.GetObject("groupe1"), GroupePersonnes)
            Console.WriteLine("groupe1={0}", groupe1)
        End Sub

    End Class
End Namespace

Die Methode [demo3] ruft das Singleton [groupe1] ab und zeigt es an.

Die Struktur des Visual Studio-Projekts bleibt unverändert, abgesehen davon, dass es zwei zusätzliche Klassen sowie eine zusätzliche Konfigurationsdatei enthält.

Image

Die Ausführung der Methode [demo3] des Tests NUnit liefert folgende Ergebnisse:

Image

Anmerkungen:

***** istia.st.springioc.tests.NunitTestSpringIocDemo3.demo3
setup test
init personne [Simon,40]
init personne [Brigitte,20]
init GroupeDePersonnes [membres=([Simon,40],[Brigitte,20]), groupes de travail=([Brigitte,Marketing] [Simon,Ressources humaines] ]
groupe1=[membres=([Simon,40],[Brigitte,20]), groupes de travail=([Brigitte,Marketing] [Simon,Ressources humaines] ]
destroy GroupeDePersonnes [membres=([Simon,40],[Brigitte,20]), groupes de travail=([Brigitte,Marketing] [Simon,Ressources humaines] ]
destroy personne [Simon,40]
destroy personne [Brigitte,20]
teardown test
  • Zeile 2: Attributmethode [Setup], die vor jedem Test ausgeführt wird, hier [demo]
  • Zeile 3–4: Spring beginnt mit der Erstellung des Singletons [groupe1]. Dieses ist von den Singletons [personne1, personne2] abhängig, die noch nicht existieren. Diese werden erstellt und ihre Methoden [init] ausgeführt.
  • Zeile 5: Das Singleton [groupe1] kann nun erstellt werden. Seine Methode [init] wird daraufhin ausgeführt.
  • Zeile 6: Die Methode [demo3] gibt den Wert des Singletons [groupe1] aus
  • Zeilen 7–10: Die Methode [TearDown] des Tests wird ausgeführt. Die Singletons werden zerstört, wodurch ihre Methoden [destroy]