2008-11-17 6 views
11

Ich habe in den letzten paar Monaten darum gekämpft, einen sauberen Code zu erstellen, um einem Benutzer den Fortschritt zu melden. Alles scheint immer zu laufen auf: „Es muss ein sauberer Weg zu sein“Wie wird der sauberste Code erstellt, wenn der Fortschritt an einen Benutzer gemeldet wird?

ReportProgress("Starting Task 1"); 
doTask1(); 
ReportProgress("Task 1 is done"); 

ReportProgress("Starting Task 2"); 
doTask2(); 
ReportProgress("Task 2 is done"); 

//etc... where report progress does some form of output to the user. 

Die gute Coder in mir schreit Aber ich bin ratlos. Irgendwelche Gedanken?

EDIT :: Ich suche mehr nach Informationen über Architekturinformationen im Gegensatz zu Implementierung spezifisch. Der angegebene Code ist sehr übermäßig vereinfacht.

+0

Welche Sprache verwenden Sie? C#? Java? –

Antwort

9

Richten Sie Ihre Aufgaben als Ereignisstrom ein, und lassen Sie den ereignisverarbeitenden "engine" -Berichtsprozess fortfahren. Jede Ereignisinstanz kann ihren eigenen Namen, Fortschrittsbericht, Klappentext usw. haben, wenn Sie so weit gehen möchten

Wenn dies ein Muster ist, das häufig auftritt, ist es den Aufwand für die Infrastruktur wert.Wenn Sie fertig sind, könnte der verwendbaren Code in etwa so aussehen:

EventQueue tasks = new EventQueue(); 
tasks.Add(new TaskEvent(this.doTask1,"Foo-ing the bar")); 
tasks.Add(new TaskEvent(this.doTask2,"Bar-ing the foo")); 
tasks.Add(new TaskEvent(this.doTask3,"Glitching and whinging")); 
... 
tasks.Execute(this.ProgressEventHandler); 
+0

Wow, ein Minty-Code-Geruch. :) +1 –

+0

@ [Allain Lalonde]: Danke, es ist so frisch, dass du immer noch den Compiler riechen kannst! –

3

Könnten Sie vielleicht Aspect Oriented Programming verwenden und einen Progress-Aspekt entwickeln?

Es gibt eine Reihe von AOP-Implementierungen. In der Java-Welt sind die zwei häufigsten Aspekte AspectJ und Spring (die entweder AspectJ oder Proxy-basierte Aspekte verwenden).

+0

lol - ja auf alle Fälle ein ganz neues Paradigma lernen, um ein einfaches Problem zu lösen! –

+0

Ich denke, es hängt von der Menge des Codes ab. Für einen kleinen Code ist dann sicher ein In-Code-Fortschrittsansatz immer der einfachste. Aber wenn die Menge an Code zunimmt, haben Sie mehr Code für die Fortschrittsberichterstattung, was die Kernlogik selbst verschleiert. Nur meine Meinung. – toolkit

+0

@Steven A. Lowe: Ich frage mich, ob die Leute ähnlich auf die Empfehlung reagierten, Objekte zu verwenden, wenn die objektorientierte Programmierung noch in den Kinderschuhen steckte. –

1

Es wäre natürlich, die Berichte innerhalb der doTask() -Aufrufe zu haben.
Typischerweise würde der Reporter ein Singleton sein, dass alle Objekte für die Entscheidung, ob und wo reponsible Nachrichten und eine Reporter-Klasse war geschickt, es zu zeigen - Statusbar, Protokolldatei, stderr usw.

+0

Dies koppelt die Methoden an die Reporter-Klasse, was bedeutet, dass Sie die Methode nicht ohne Bericht aufrufen können (oder einen Parameter hinzufügen, um zu steuern, ob Sie den Reporter anrufen oder nicht). Das kann OK sein - sag einfach. – MusiGenesis

+0

Normalerweise lassen Sie das Reporter-Objekt entscheiden, ob es berichten wird. Es sei denn, Sie sind besorgt über den Aufwand für die Berichterstattung von Texten, die nicht verwendet werden. –

1

das Muster in dem, was Sie Angenommen‘ re zu tun ist:

  • log Aufgabe Aufgabe
  • tun beginnen
  • log Aufgabe Ende

Sie haben "Task" -Klasse (übergeordnete für alle Ihre Aufgaben), deren do() -Methode Unterklasse ist und automatisch Start und Ende der Aufgabe protokolliert.

Nur eine Idee.

0

Sie Report aus dem Inneren der Methoden doTask nennen könnte, das könnte es ein wenig sauberer aussehen, stattdessen würden Sie gerade haben:

doTask1(); 
doTask2(); 

Die Berichterstattung innerhalb dieser Methoden behandelt werden würde.

Sie könnten AOP verwenden, aber mein Gehirn schreit KISS !! (Keep It Simple Stupid) in diesem Fall. Wenn dies nur eine einfache Darstellung von etwas Komplizierterem ist, mit dem Sie es zu tun haben, könnte AOP eine Option sein.

3

Sie könnten eine Task-Klasse mit einer Namenseigenschaft und einem Delegate erstellen. Fügen Sie jede Aufgabe in eine Sammlung ein, durchlaufen Sie sie, drucken Sie die Nachricht und rufen Sie den Delegierten für jede Aufgabe auf.

1

Ich würde die numerischen Teile der angezeigten Nachrichten nicht manuell codieren (jedes Mal, wenn Sie Aktionen hinzufügen oder entfernen oder die Reihenfolge ändern müssen, die Sie ausschneiden und einfügen müssen). Sie möchten, dass jedes Objekt, das die ReportProgress-Methode verarbeitet, sich selbst automatisch erhöht, während es fortschreitet.

1

Eine recht einfache und saubere Weise wäre eine abstrakte Klasse zu erstellen, die eine do() Methode und abstrakte doTask() und getName() Methoden hat:

do() { 
    ReportProgress("Starting " + this.getName()); 
    doTask(); 
    ReportProgress("Finished " + this.getName()); 
} 

dann in Ihre Aufgaben:

class Task1 extends Task { 
    getName(){return "Task 1";} 
    doTask() { 
     //do stuff here 
    } 
} 

Sie dann eine Aufgabe haben könnte, die eine doTask() Methode hat, die do() auf eine ganze Reihe von o läuft weitere Aufgaben Dies könnte leicht rekursiv sein, da jede Task dann eine Reihe von Unteraufgaben ausführen könnte.

1

+1 auf dem AOP-Vorschlag. Dies ist eine klassische Querschnittsaufgabe, die AOP elegant lösen würde.

0

Leider hängt der beste Weg, dies zu tun, von den Details ab - zumindest von der Sprache, die Sie verwenden. Zum Beispiel in Python Sie eine context manager ermöglichen das Schreiben von Code wie folgt verwenden:

with progress_report("Task 1"): 
    do_task_1() 

Dies könnte beispielsweise dafür sorgen, dass die „Task 1 erfolgt“ wird berichtet, auch wenn do_task_1() eine Ausnahme auslöst. Wenn Sie möchten, können Sie Ausnahmen separat verarbeiten und etwas anderes ausgeben, wie "Aufgabe 1 fehlgeschlagen" oder "Aufgabe 1 abgebrochen".

0

In unserem Toolkit haben wir einen Task-Controller, der Aufgaben verwaltet. Eine Aufgabe wird als Thread ausgeführt. Zusätzlich zur typischen Thread-Unterstützung unterstützt eine Task Fortschrittsmethoden. Eine mögliche Sicht auf den Fortschritt ist ein visueller Fortschrittsbalken mit einem Titel, der sich auf den Aufgabennamen und den Schritt innerhalb der Aufgabe bezieht. Um die sichtbaren Statistiken und den Status zu unterstützen, muss der Code gelegentlich Aufrufe an die Fortschrittsmethode der Aufgabe senden. In der Regel erfolgt dies innerhalb von for-Schleifen, da der prozentuale Fortschritt durch den aktuellen Index dividiert durch die Grenze geschätzt werden kann.

Der Task-Controller ist ein nützlicher Ort, um globale Thread-Steuerung, Status-Probes, andere Statistiken und Leistungsmessungs-Hooks hinzuzufügen. Einige Multithread-Fehler und Timing-Probleme können analysiert werden, indem der Status des Controllers und der Status aller Tasks untersucht werden.

2

Es hängt davon ab, wie viel config im laufenden Betrieb benötigt wird, ich würde erwarten, dass der Code sehr allgemein ist und die Aufgaben über die Feder oder einen beliebigen ioc Container eingerichtet werden müssen.

Dies wäre alles in einer Feder config: Die XML-Konfiguration würde das Task-Objekt mit seinem Namen und Parametern liefern. Fügen Sie dann diese Aufgaben zu einer Sammlung hinzu und übergeben Sie diese Sammlung dem Task-Runner.

Der Task-Runner ist dann ein Code, der den Stopp und den Start jeder Aufgabe signalisiert, aber jeder Task kann dann einen bestimmten Status geben, wie er läuft. Auch der Taskrunner wird alle Ausnahmen abfangen und weitermachen, wenn etwas ausbricht. Es könnte konfigurierbar gemacht werden, um zu sagen, dass bestimmte Aufgaben von der Fertigstellung anderer abhängen, und einige Aufgaben sollten alles anhalten, wenn sie fehlschlagen.

Ich stimme nicht zu, dass AOP hier verwendet werden sollte. Overkill.

0

Wenn Sie .NET verwenden, würde ich vorschlagen, die Policy Injection Application Block von Enterprise Library (Minimum Version: 3.1) zu verwenden. Ich benutzte ein ähnliches Zeug, um eine "Identität des Anwendungspools wiederherzustellen" für eine Website, die sich stark mit Identitätswechsel beschäftigte.

Sie könnten das gleiche mit Ihrer Aufgabe tun. Sie können einfach eine Aufgabenklasse mit einer Factory definieren, die das Objekt mit der Enterprise-Bibliothek-Objektfactory erstellt und automatisch eine "Before" - und "After" -Nachricht zur Aufgabe hinzufügt. Das würde GENAU geben, was Sie mit der erforderlichen Eleganz wünschen.

Viel Spaß!