Dojos für Entwickler 2. Stefan Lieser

Чтение книги онлайн.

Читать онлайн книгу Dojos für Entwickler 2 - Stefan Lieser страница 8

Автор:
Серия:
Издательство:
Dojos für Entwickler 2 - Stefan Lieser

Скачать книгу

      Listing 10

      Den Flow zusammensetzen.

      public class Eindeutige_Stichwörter_ermitteln { private Action<Tuple<string, string>> process; public Eindeutige_Stichwörter_ermitteln() { var dateinamen_suchen = new Dateinamen_suchen(); var alle_Stichwörter_ermitteln = new Alle_Stichwörter_ermitteln(); var eindeutige_Stichwörter_filtern = new Eindeutige_Stichwörter_filtern(); dateinamen_suchen.Result += alle_Stichwörter_ermitteln.Process; alle_Stichwörter_ermitteln.Result += eindeutige_Stichwörter_filtern.Process; eindeutige_Stichwörter_filtern.Result += x => Result(x); process = path_und_SearchPattern => dateinamen_suchen.Process( path_und_SearchPattern); } public void Process(Tuple<string, string> path_und_SearchPattern) { process(path_und_SearchPattern); } public event Action<IEnumerable< string>> Result; }

      Ich habe hier bewusst keine Dependency Injection betrieben, sondern in der Platine werden die benötigten Bauteile direkt mit new instanziert. Die Abhängigkeiten über den Konstruktor zu injizieren hätte mir den Vorteil gebracht, dass ich dann im Test gegen Attrappen hätte testen können. Doch das ist mir für Platinen viel zu mühsam. Denn es liefe dann auf Tests hinaus, in denen ein Mock-Framework zum Einsatz kommen muss, um damit die Attrappen zu erzeugen. Weil die Platine selbst keine Logik enthält, sondern nur für die Verdrahtung der Bauteile zuständig ist, begnüge ich mich mit einem ohnehin notwendigen Integrationstest. Der Erkenntnisgewinn wäre durch einen Unit-Test der Platine, der dann auf Attrappen setzen müsste, nicht größer.

      Das Verdrahten der Bauteile geschieht im Konstruktor der Platine. Nachdem die benötigten Bauteile instanziert sind, werden sie in der richtigen Reihenfolge verdrahtet, indem jeweils eine Process-Methode an einen Result-Event gebunden wird. Am Ende der Kette muss der Result-Event des letzten Bauteils den Result-Event der Platine auslösen. Da zum Zeitpunkt der Verdrahtung innerhalb des Konstruktors noch niemand an den Result-Event der Platine gebunden sein kann, erfolgt die Weiterleitung an diesen Event mittels Lambda-Expression. Um beim Aufruf der Process-Methode der Platine die Process-Methode des ersten Bauteils aufrufen zu können, wird der korrekte Aufruf in eine Action als Feld der Klasse abgelegt.

      Der Integrationstest zur Platine arbeitet auf denselben Testdaten wie die Tests der Bauteile. Dadurch war der Integrationstest in Listing 11 schnell fertiggestellt. Der Test ermittelt die Stichwörter aller JPEG-Dateien im Verzeichnis testdaten. Anschließend wird über Assert überprüft, ob die korrekten Stichwörter vorliegen.

      Listing 11

      Integrationstest.

      [TestFixture] public class Eindeutige _Stichwörter_ermitteln_Tests { private Eindeutige _Stichwörter_ermitteln sut; private IEnumerable<string> result; [SetUp] public void Setup() { sut = new Eindeutige _Stichwörter_ermitteln(); sut.Result += x => result = x; } [Test] public void Integrationstest() { sut.Process(new Tuple<string, string>("testdaten", "*.jpg")); Assert.That(result.ToArray(), Is.EqualTo(new[] { "A", "B", "C", "D", "E" })); } }

      Eine App

      Als letzter Schritt musste nun die Platine noch in eine Konsolenanwendung integriert werden, siehe Listing 12.

      Listing 12

      Integration in eine Konsolenanwendung.

      public static class Program { public static void Main(string[] args) { var eindeutige_Stichwörter_Ermitteln = new Eindeutige_Stichwörter_ermitteln(); eindeutige_Stichwörter_Ermitteln.Result += stichwörter => { foreach (var stichwort in stichwörter) { Console.WriteLine(stichwort); } }; eindeutige_Stichwörter_Ermitteln.Process( new Tuple<string, string>( args[0], args[1])); } }

      Ich habe mich entschieden, den Pfad und die Suchmaske aus den Parametern der Kommandozeile zu entnehmen. Hier erfolgt keine Prüfung, ob die Parameter vorliegen. In einer realen Anwendung würde man sicherlich prüfen, ob das args-Array passend gefüllt ist.

      An den Result-Event der Platine wird eine Lambda-Expression gebunden, welche die ermittelten Stichwörter mit Console.Write­­Line auf der Konsole ausgibt. Hier stellt sich natürlich die Frage, ob es tatsächlich die Aufgabe der Anwendung sein sollte, sich um die Konsolenausgabe zu kümmern. Zumindest die Main-Methode sollte sich damit nicht unmittelbar befassen. Daher habe ich die Konsolenausgabe in das Bauteil Auf_Konsole_aus­geben ausgelagert, siehe Listing 13. Damit reduziert sich die Main-Methode auf den Code in Listing 14.

      Listing 13

      Konsolenausgabe auslagern.

      public class Auf_Konsole_ausgeben { public void Process( IEnumerable<string> zeilen) { foreach (var zeile in zeilen) { Console.WriteLine(zeile); } } }

      Listing 14

      Das Hauptprogramm.

      public static class Program { public static void Main(string[] args) { var eindeutige_Stichwörter_Ermitteln = new Eindeutige_Stichwörter_ermitteln(); var auf_Konsole_ausgeben = new Auf_Konsole_ausgeben(); eindeutige_Stichwörter_Ermitteln.Result += auf_Konsole_ausgeben.Process; eindeutige_Stichwörter_Ermitteln.Process( new Tuple<string, string>( args[0], args[1])); } }

      Fazit

      Die Aufgabe hat in der Vorbereitung mehr Zeit in Anspruch genommen, als ich vermutet hatte. Das lag daran, dass die Softwarehersteller sich dazu entschlossen haben, die Stichwörter nicht gleich in den JPEG-Dateien abzulegen. Die Herausforderung, die Hierarchie in den Stichworten darzustellen, konnte ich gar nicht meistern, da diese Information beim Export aus dem Elements Organizer verloren geht. Doch keine Sorge, es wird eine weitere Iteration des Programms geben. Schauen Sie sich einfach die neue Aufgabe in diesem Heft an!

       [ml]

      [1] NUnit, www.nunit.org [2] ReSharper, www.jetbrains.com/resharper

      Aufgabe 3

      Bilddateien parallel verarbeiten

      Alle anpacken!

      Sie sollen aus vielen JPEG-Dateien die Stichworte extrahieren. Eine ideale Aufgabenstellung für Parallelverarbeitung. Aber läuft das Programm damit auch wirklich schneller?

      Versuch macht klug. Daher soll es in der Aufgabe für diesen Monat darum gehen herauszufinden, ob die Parallelverarbeitung von Dateien das Programm beschleunigen kann. Natürlich soll dabei Flow-Design zum Einsatz kommen. Denn Flow-Design hat im Bereich der Parallelisierung einen entscheidenden Vorteil : Ein Entwurf, der zunächst ohne den Aspekt der Parallelisierung erstellt wurde, kann leicht um Parallelverarbeitung ergänzt werden. Das gilt natürlich nur, wenn überhaupt einzelne Schritte im Flow parallel ausführbar sind, ohne dass dadurch die Semantik verändert wird. Bei der Parallelisierung von Flows lassen sich zwei Fälle unterscheiden:

       Es existieren im Flow bereits parallele Datenflüsse, die allerdings bislang sequenziell ausgeführt werden.

       Es werden Aufzählungen von Daten verarbeitet, sodass sich eventuell mehrere Instanzen parallel um die Verarbeitung kümmern

Скачать книгу