Laden...

Auf Ereignisse reagieren, wie sieht der Designansatz aus?

Erstellt von salla vor 17 Jahren Letzter Beitrag vor 17 Jahren 2.233 Views
S
salla Themenstarter:in
147 Beiträge seit 2005
vor 17 Jahren
Auf Ereignisse reagieren, wie sieht der Designansatz aus?

Hallo,

Ich habe eine Klasse (CWetterAnfrage) die auf Anfragen von anderen Klassen Wetterinfoobjekte erzeugt (wird jeweils in einem neuen thread erzeugt). Die Abfrage der Wetterstation dauert etwas, daher können pro Minute etwa nur 2 - 3 Wetterinfoobjekte erzeugt werden. Daher sollen die Anfragen in CWetterAnfrage in einer Queue abgelegt und der Reihe nach abgearbeitet werden.

Soweit so gut. Wie genau die Kommikation zwischen CWetterAnfrage und der "aufrufenden Klasse" ablaufen soll, ist mir noch nicht ganz klar. Mit Delegate und Events müsste das gehen. Ich weiss nur noch nicht genau wie.

Hätte ich nur eine aufrufende Klasse (CAufrufendeKlasse1) würde ich das so machen (der Übersicht wegen, ohne Parameter und verarbeitenden Code):


public class CAufrufendeKlasse1
{
   public CAufrufendeKlasse1
   {
      Tasks.CWetterAnfrage.OnGetWetterobjekt += new Tasks.CWetterAnfrage.OnGetWetterobjektDelegate(CWetterAnfrage_OnGetWetterobjekt);
   }
   
   private WetterAnfrage()
   {
      Tasks.IApiWetter task = new Tasks.CWetterAnfrage();
      Thread thread = new Thread(new ThreadStart(task.PerformTask));
      thread.IsBackground = true;
      thread.Start();
   }

   private void CWetterAnfrage_OnGetWetterobjekt(CWetterobjekt wetter)
   {
      // verarbeitender code ...
   }
}

public class CWetterAnfrage : IApiWetter
{
   public delegate void OnGetWetterobjektDelegate(CWetterobjekt oWetter);
   public static event OnGetWetterobjektDelegate OnGetWetterobjekt;
      
   public CWetterAnfrage()
   {
       Tasks.CAnfrageQueue.OnAnfrageFertig += new Tasks.CAnfrageQueue.OnAnfrageFertigDelegate(CAnfrageQueue_OnAnfrageFertig);
   }

   public void PerformTask()
   {
      // Anfrage in die Queue stecken
   }

   private void CAnfrageQueue_OnAnfrageFertig(CWetterobjekt wetter)
   {
      if (OnGetWetterobjekt != null)
      {
         OnGetWetterobjekt(wetter);
      }
   }
}


Wenn ich nun mehrere aufrufende Klassen habe, wie ist das zu programmieren? Wie kann ich dafür sorgen, dass das OnGetWetterobjekt Event zu der richtigen Klasse kommt? Oder habe ich einen falschen Designansatz gewählt, falls ja, welcher ist der richtige?

Vielen Dank für eure Hilfe.

B
1.529 Beiträge seit 2006
vor 17 Jahren

Ich würde das ehrlich gesagt ganz anders gestalten. Die Wetterstation sollte von einer (statischen) Klasse so oft wie möglich nach allen Daten abgefragt werden.
Die Klasse sollte dann ein Event bereitstellen, dass immer aufgerufen wird, wenn neue Daten verfügbar sind. Zusätzlich gibt es eine Methode, die die letzte Messung zurückliefert.

Wenn sich dann jemand registriert, kann er sofort die letzte Messung abfragen. Ansonsten wird er informiert, wenn neue Daten bereit stehen und kann sich diese abholen.

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo salla,

meiner Meinung nach ist der Designansatz, sorry, kompletter Murx oder ich habe den tieferen Sinn nicht verstanden. Wie es richtig geht steht in [FAQ] Eigenen Event definieren

BTW: Klassennamen sollen keinen Prefix haben.

herbivore

S
salla Themenstarter:in
147 Beiträge seit 2005
vor 17 Jahren

Original von Borg
Ich würde das ehrlich gesagt ganz anders gestalten. Die Wetterstation sollte von einer (statischen) Klasse so oft wie möglich nach allen Daten abgefragt werden.
Die Klasse sollte dann ein Event bereitstellen, dass immer aufgerufen wird, wenn neue Daten verfügbar sind. Zusätzlich gibt es eine Methode, die die letzte Messung zurückliefert.

Wenn sich dann jemand registriert, kann er sofort die letzte Messung abfragen. Ansonsten wird er informiert, wenn neue Daten bereit stehen und kann sich diese abholen.

Genau das sollte eigentlich vermiden werden. Abfragen nur, wenn die Daten auch benötigt werden.

Original von herbivore
meiner Meinung nach ist der Designansatz, sorry, kompletter Murx

Kein "sorry" nötig. Ich bin mit dem Designansatz ja auch nicht zufrieden, deswegen auch die Nachfrage. Mit meinem momentanen Wissensstand habe ich keinen besseren Ansatz gefunden.

Ich versuche das Problem einfach noch einmal generell auszudürcken. Vielleicht habe ich euch mit meinem Ansatz auch schon in die falsche Richtung geführt.

Problem: Eine DLL stellt eine Schnittstelle bereit die Objekte - wir nennen es O - erzeugt. Pro Minute können maximal 3 O erzeugt werden (verschiedene!). Innerhalb des Programmes werden von unterschiedlicher Stelle (= unterschiedlicher Klasse) diese O angefordert. Das kann durchaus Zeitgleich und öfters als 3 mal pro Minute passieren.

Wie läßt sich das Programmtechnisch lösen?

Danke für eure Hilfe.

49.485 Beiträge seit 2005
vor 17 Jahren

Halllo salla,

dann sollen die Objekte in einer Fabrikmethode ihrer Klasse erstellt werden, die die drei-Minuten-Mimik realisiert. Sprich aus meiner Sicht, braucht man nur eine statische Methode oder ich habe den tieferen Sinn immer noch nicht verstanden.

herbivore

T
512 Beiträge seit 2006
vor 17 Jahren

Also irgendwie hab ich auch noch Zweifel, dass ich das richtig verstanden habe.

Du hast also 2 asynchrone Aktivitäten:

  1. In der einen werden irgendwie Objekte erzeugt (Erzeuger)
  2. In der anderen werden irgendwie die Objekte verarbeitet (Verbraucher)

Und du willst vermeiden, dass die Verbraucher die ganze Zeit nachschauen ob etwas da ist (busy waiting)

Außerdem gibt es mehrere unterschiedliche Verbraucher, die jeweils auch nach unterschiedlichen Datenarten anfragen.

Haut das soweit erstmal hin?

e.f.q.

Aus Falschem folgt Beliebiges

S
salla Themenstarter:in
147 Beiträge seit 2005
vor 17 Jahren

Haut das soweit erstmal hin?

Das trifft es zu 100%.

T
512 Beiträge seit 2006
vor 17 Jahren

Ich versteh es noch nicht so recht.

Das Problem was ich dabei habe ist, dass die Objekte ja auf Anfrage erstellt werden. Das heißt du willst im Prinzip nen Ablauf in der Art:

  1. Anfragen
  2. Warten bis Anfrage fertig
  3. Verarbeiten

Das ist ja genau der Ablauf, wenn du das ganze in einem einzigen Thread laufen lassen würdest. Ich verstehe nicht so recht warum das Bearbeiten der Anfrage in nem anderen Thread laufen muss, wenn der anfragende Thread in der Zeit eh nur wartet.

Oder alternativ willst du vieleicht, dass ein Thread eine Anfrage erzeugt und dann was ganz anderes macht. Du erzeugst dann einen Thread, der die Daten holt. Aber genau dieser Thread der die Daten geholt hat, kann doch im Anschluss gleich verarbeiten.

Oder dein Problem bei der Sache ist lediglich, dass durch dumme Zufälle plötzlich zu viele Threads aktiv sind, dann benutze einfach den ThreadPool. Wenn du die Threads mit dem ThreadPool erzeugst, löst sich das Problem. Der lässt nur eine bestimmte Anzahl an Threads gleichzeitig zu. Wenn mehr angefragt werden, steckt er die völlig selbstständig in eine Queue. Wenn du nicht den kompletten ThreadPool damit verstopfen willst, müsstest du aber noch bisschen was mehr tun.

Oder du willst, dass Thread 1 die Anfrage stellt, von Thread 2 ein Objekt erzeugt wird, und Thread 1 die wieder verarbeitet, und Thread 1 in der Zeit wo Thread 2 arbeitet selbst noch was ganz anderes machen soll. Da gibt es keine andere Lösung als regelmäßig abfragen, ob was fertig ist. Du kannst einen Thread nicht unterbrechen und ganz woanders fortsetzen lassen.
Entweder warten und nichts tun, oder ständig prüfen. Dazu gibt es keine Alternativen.

e.f.q.

Aus Falschem folgt Beliebiges

B
1.529 Beiträge seit 2006
vor 17 Jahren

Genau das sollte eigentlich vermiden werden. Abfragen nur, wenn die Daten auch benötigt werden.

Du kannst doch im Adder/Remover des Event speichern, ob sich jemand verbunden hat. Und nur wenn das der Fall ist, werden Daten gelesen.
Wie oben schon geschrieben: viele andere Möglichkeiten hast du nicht.

S
salla Themenstarter:in
147 Beiträge seit 2005
vor 17 Jahren

Du kannst doch im Adder/Remover des Event speichern, ob sich jemand verbunden hat. Und nur wenn das der Fall ist, werden Daten gelesen.

🤔

Ich hab hab den Denkfehler die ganze Zeit an der falschen Stelle gesucht, bzw. im Designansatz. Dabei war mein Fehler, nicht das Event mit in der Queue abzuspeichern.

Danke für eure gedult und hilfsbereitschaft. Das nächste mal werde ich doch den kompletten Code posten. Bringt wohl nichts wenn man den Code leichter lesbar machen möchte, und dann den Fehler mit heraus nimmt. 🙁

Noch mal ein dickes DANKESCHÖN an euch.

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo salla,

Das nächste mal werde ich doch den kompletten Code posten.

ansich ist es eine gute und erwünschte Entscheidung, nur Ausschnitte zu posten. Es ist im Gegenteil so, dass Fragen, die massig Code enthalten, öfter ignoriert werden, als welche mit kurzen Code-Ausschnitten.

Bringt wohl nichts wenn man den Code leichter lesbar machen möchte, und dann den Fehler mit heraus nimmt.

Das ist eine Konsequenz, die wir gerne in Kauf nehmen und eine Lösung verhindert, hat der Umstand ja nicht. Uns ist eine Frage wesentlich lieber, wenn die Vorarbeit und das eigene Bemühen des Fragestellers erkennbar ist. Die Vorarbeit und Selektion hilft uns im Schnitt mehr, als dass sie schadet.

herbivore

S
salla Themenstarter:in
147 Beiträge seit 2005
vor 17 Jahren

Danke herbivore für die Rückmeldung. Das spiegelt auch meine eigentliche Ansicht zum Thema Codeposting. Dann werde ich das auch in Zukunft weiterhin so handhaben wie bisher.

Nochmal danke an alle.