b2aat6n
b2aat6n
b2aat6n
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
Listing 8<br />
Auf einen leeren Stack testen.<br />
[Test]<br />
public void Enthaelt_nach_der_Entnahme_des_top_Elementes_keine_weiteren_Elemente()<br />
{<br />
sut.Pop();<br />
Assert.That(sut.top, Is.Null);<br />
}<br />
Listing 9<br />
Mehrere Push-Aufrufe.<br />
[Test]<br />
public void Macht_das_naechste_uebergebene_Element_zum_top_Element() {<br />
sut.Push("b");<br />
Assert.That(sut.top.Data, Is.EqualTo("b"));<br />
}<br />
[Test]<br />
public void Legt_das_vorhandene_Element_bei_Uebergabe_eines_weiteren_unter_dieses() {<br />
sut.Push("b");<br />
Assert.That(sut.top.Next.Data, Is.EqualTo("a"));<br />
}<br />
in einem ersten Test geprüft werden, ob<br />
dieses Element bei Aufruf der Pop-Methode<br />
zurückgegeben wird, siehe Listing 7.<br />
Nun kann überprüft werden, ob der<br />
Stack denn nach dem Pop auch wieder leer<br />
ist, siehe Listing 8. Und jetzt hilft alles<br />
nichts, wir müssen uns mit mehr als einem<br />
Push befassen. Dabei kommt es darauf an,<br />
das neue Element vor das bisherige top-<br />
Element einzuordnen. Dazu muss der top-<br />
Zeiger geändert werden sowie der Next-<br />
Zeiger des top-Elements. Listing 9 zeigt die<br />
entsprechenden Tests.<br />
Daraus ergibt sich dann die fertige Implementierung<br />
des Stacks wie in Listing 10.<br />
Reflexion<br />
Die testgetriebene Vorgehensweise hat mir<br />
keine großen Probleme bereitet. Das lag<br />
zum Großteil daran, dass ich meine Skizze<br />
zur Hand hatte. So konnte ich bei Fragen<br />
sofort nachsehen, wie die top- und Next-<br />
Zeiger jeweils aussehen müssen. Und dadurch,<br />
dass die Tests auf die Interna zugreifen<br />
können, musste ich nicht schon für den<br />
ersten Test gleich zwei Methoden implementieren.<br />
Das ist ein großer Vorteil, der<br />
bei einem so kleinen Beispiel wie einem<br />
Stack möglicherweise nicht so deutlich<br />
wird. Ich habe diesen Effekt jedoch schon<br />
in einigen Fällen als vorteilhaft empfunden,<br />
bei denen es um den internen Zustand<br />
von Klassen ging. Immer da, wo<br />
mehrere Methoden auf einem internen Zustand<br />
arbeiten, kann es sich lohnen, den<br />
Zustand für die Tests sichtbar zu machen,<br />
um bei der Implementierung Methode für<br />
Methode vorgehen zu können.<br />
Queue<br />
Bei der Warteschlange bin ich so verfahren<br />
wie schon beim Stack: Ich habe mir überlegt,<br />
wie man eineWarteschlange in einer Datenstruktur<br />
darstellen kann. Meine Überlegung<br />
hier: Bei einer Warteschlange sollte es offensichtlich<br />
zwei Zeiger geben, die jeweils auf<br />
ein Element verweisen. Zum einen auf das<br />
zuletzt eingefügte Element, um dort bei der<br />
Enqueue-Methode ein weiteres Element ergänzen<br />
zu können, sowie einen Zeiger auf<br />
das nächste zu entnehmende Element für<br />
die Dequeue-Methode. In meiner ersten<br />
Skizze malte ich also das erste und letzte<br />
Element einer Warteschlange und verwies<br />
darauf jeweils mit den Zeigern enqueue und<br />
dequeue, wie es Abbildung 2 zeigt.<br />
Listing 10<br />
LÖSUNG<br />
Die fertige Implementierung<br />
des Stacks.<br />
public class Stack :<br />
IStack {<br />
internal Element top;<br />
public TElement Pop() {<br />
if (top == null) {<br />
throw new<br />
InvalidOperationException();<br />
}<br />
var result = top.Data;<br />
top = top.Next;<br />
return result;<br />
}<br />
public void Push(TElement element) {<br />
var newTop = new Element {<br />
Data = element,<br />
Next = top<br />
};<br />
top = newTop;<br />
}<br />
}<br />
Im Anschluss habe ich überlegt, wie die<br />
Elemente untereinander sinnvoll zu verbinden<br />
sind. Dabei gibt es mehrere Möglichkeiten:<br />
❚ Jedes Element zeigt mit Next auf das ihm<br />
folgende.<br />
❚ Jedes Element zeigt mit Prev auf das<br />
hinter ihm liegende.<br />
❚ Jedes Element enthält sowohl Next- als<br />
auch Prev-Zeiger.<br />
Die doppelte Verkettung habe ich nicht<br />
weiter berücksichtigt, da ich vermutete,<br />
dass es auch ohne gehen muss. Dabei stand<br />
nicht der Reflex im Vordergrund, dass eine<br />
doppelteVerkettung mehr Speicher braucht<br />
als eine einfache. Ich dachte eher daran,<br />
dass ich bei doppelter Verkettung beim Einfügen<br />
und Entfernen von Elementen zwei<br />
Zeiger korrigieren muss. Das erschien mir in<br />
jedem Fall mühsamer, als nur einen Zeiger<br />
korrigieren zu müssen. Es siegte sozusagen<br />
die pure Faulheit.<br />
Es blieb noch die Frage zu klären, ob<br />
Next- oder Prev-Zeiger sinnvoller sind. Das<br />
habe ich mir wieder anhand meiner Skizze<br />
überlegt. Wenn ein neues Element in die<br />
Warteschlange eingefügt wird, muss enqueue<br />
anschließend auf das neue Element<br />
zeigen. Bei Verwendung von Next-Zeigern<br />
muss dann nichts korrigiert werden, bei<br />
Prev-Zeigern muss das bisher erste Element<br />
auf das neue erste zurückverweisen.<br />
Beides ist kein Problem, es ergibt sich also<br />
hier noch keine Präferenz für eines der bei-<br />
www.dotnetpro.de dotnetpro.dojos.2011 41<br />
[Abb. 2]<br />
enqueue-<br />
und<br />
dequeue-<br />
Zeiger.