dedlfix: Konkretes Beispiel

Beitrag lesen

Tach!

  1. Problem: In den Kommando-Objekten kommt immer irgendwo eine Schleife von ungefähr dieser Form vor:

while ((line = stringReader.GetLine()) != null) {

string[] tokens = line.Split(';'); // Zeile parsen
  // ... Zeile weiter verarbeiten.
}


> Für mich ist es naheliegend, die Schleife in eine Methode ` public List<MyXmlObject> GetObjects()`{:.language-java} einzubetten. Das Problem dabei ist: Natürlich will ich sowohl in der CLI- als auch in der GUI-Variante (in einem Textfeld o.ä.) eine Statusausgabe, die mir sagt, wenn eine Zeile nicht geparst werden konnte. Nachdem das auch mit der GUI funktionieren soll, ist nix mit `WriteLine("Fehler in Zeile xyz");`{:.language-java} in der Schleife.  
> Eine saubere Lösung dafür fällt mir nicht ein. Wie mache ich das??  
  
Ohne mich genau au die Gegebenheiten zu erinnern, fällt mir da zumindest Debug als Stichwort ein. Ist es nicht so gewesen, dass man einerseits Debug-Meldungen schreiben kann und andererseits einen Listerner braucht, der darauf reagiert und etwas unternimmt?  
  
Andererseits, wenn du einen Rückkanal brauchst, solltest du diesen Rückkanal dem Kommando-Objekt mit übergeben. Da gibt es sicher auch irgendein Pattern mit Namen dafür. Konkret implementiert wäre das ein Delegate oder vielleicht auch ein Event, für das der Aufrufer einen Eventhandler einklinken kann.  
  
Den Status als Funktionsergebnis zurückzugeben geht sicher auch. Aber da ist es vielleicht sinnvoller, das eigentliche Ergebnis der Arbeit zurückzuliefern. Dazu später noch was.  
  

> 2. Problem: Wenn irgendwo in den Transformer- oder Kommando-Objekten Exceptions auftreten, müssen die ebenfalls mit beiden GUI-Varianten sauber ausgegeben werden. Ich muss irgendwo einen Layer in meiner Software definieren, der alle Exceptions abfängt und auf eine Weise an den aufrufenden Layer zurückgibt, die für CLI und GUI passt.  
> Auch hier stehe ich an: Wo baue ich die `catch`{:.language-java}-Klauseln ein und wie gebe ich die Fehlermeldungen an das UI zurück??  
  
In den Aufrufer. Nur der weiß im konkreten Fall, was zu tun ist. Ich würde da keine höhere (Gott-)Instanz implementieren, die für sämtliche Problemfälle aller beteiligten Komponenten eine Lösung kennen soll. Gegebenenfalls muss eine Komponente die eigentliche bei ihr auftretende Exception in eine allgemeinere oder auch spezifischere (KommandoException) kapseln.  
  

> 3. Problem (eigentlich kein Problem, nur ein ungutes Gefühl): Alle Kommando-Objekte sind irgendwie "gleich": Klar, die Execute()-Methode unterscheidet sich möglicherweise sehr stark, aber das UI tut immer  
> `transfomer.Command = new MyCommand(string inputFile, string encoding, string outputFile, bool overwrite);`{:.language-java}  
> oder  
> `transfomer.Command = new MyOtherCommand(string inputFile, string encoding, string outputFile, bool overwrite);`{:.language-java}  
> D.h., die Konstruktorparameter für die Commands sind immer gleich. Ich kann zwar nicht konkret sagen, was damit nicht stimmt, aber irgendwie habe ich kein gutes Gefühl dabei...  
  
Daran könnte nicht stimmen, dass du statt der Daten den Weg zu den Daten angibst und sich das Kommando die notwendigen Zugriffsprozeduren auch noch mit sich rumschleppen muss, selbst wenn man sie in einer Elternklasse unterbringt. Ich nehme an, "sauberer" ist es, oben Daten einzukippen und unten das Ergebnis abzuholen und Beschaffung und Wegschreiben außerhalb durch Spezialisten erledigen zu lassen. Dann kannst du diese Spezialisten bei Bedarf anpassen oder neue erstellen, ohne die bestehende Funktionalität in den Transform-Klassen zu beeinträchtigen. Zur Not übergibst du halt die fertig initialisierten Spezialisten als Parameter. So bekommst dein Transformationskommando weniger Dinge zu tun, die eigentlich gar nicht zu seinen direkten Aufgaben zählen. Vor allem auch im Hinblick auf Testbarkeit ist es auf diese Weise besser, weil da nicht irgendwelche Festplattenzugriffe mit getestet werden, sondern Dummys übergeben werden können.  
  
  
dedlfix.