Ereignisverarbeitung mit dem Entwurfsmuster Observer

In diesem Artikel möchte ich Ihnen eine Methode vorstellen, mit der Sie Oberflächenereignisse innerhalb von CONZEPT 16-Applikationen mit dem Entwurfsmuster (engl. design pattern) "Observer" (Beobachter, Listener) verarbeiten können.

Damit haben Sie die Möglichkeit mehrere Ereignisfunktionen für dasselbe Ereignis aufrufen zu können und so Applikationskomponenten, die zur gleichen Zeit die gleichen Oberflächenobjekte verwenden, unabhängig voneinander zu implementieren.

Beispielsweise können Sie das Ereignis EvtLstSelect eines DataList-Objektes in zwei unabhängigen Komponenten "A" und "B" verwenden. Komponente A könnte sich um die Aktualisierung von Steuerobjekten, wie Werkzeugleiste und Schaltflächen kümmern und Komponente B um die Anzeige zusätzlicher Informationen.

Über die nativen Funktionen WinEvtProcNameSet() und WinEvtProcNameGet() ist es bereits möglich zur Laufzeit der Applikation Ereignisfunktionen zu "registrieren" und zu ermitteln. Dabei kann allerdings pro Objekt und Ereignis immer nur eine Funktion angegeben werden.

In der am Ende des Artikels als Download bereit gestellten Prozedur befindet sich eine Implementierung des Observer/Listener-Entwurfsmusters für die CONZEPT 16-Ereignisverarbeitung bei Oberflächenobjekten.

Dabei wird beim Auslösen eines Ereignisses durch ein Oberflächenobjekt nicht nur eine Ereignisfunktion aufgerufen, sondern alle die zu diesem Zeitpunkt für dieses Ereignis in diesem Objekt registriert sind.

Die Prozedur stellt unter anderem zwei wesentliche Funktionen zur Verfügung:

  • Evt.Add(
      aWinObject : handle;    // Oberflächenobjekt
      aEvtID     : int;       // Ereignis-ID
      aCall      : alpha(61); // Ereignisfunktion
    ) : logic                 // Erfolg
  • Evt.Remove(
      aWinObject : handle;    // Oberflächenobjekt
      aEvtID     : int;       // Ereignis-ID
      aCall      : alpha(61); // Ereignisfunktion
    ) : logic                 // Erfolg

Mit der Funktion Evt.Add() kann eine Ereignisfunktion zu einem Objekt und einem Ereignis hinzugefügt und mit Evt.Remove() wieder entfernt werden.

Die beiden Funktionen haben die gleiche Signatur, also die gleichen Argument- und Rückgabetypen, wie die Funktion WinEvtProcNameSet(). Im Gegensatz zu dieser Funktion, werden die Ereignisfunktionen bei Evt.Add() und Evt.Remove() dem Oberflächenobjekt nicht direkt als Ereignisfunktion zugewiesen, sondern in einer Liste im Speicher vorgehalten und zu gegebenem Zeitpunkt aufgerufen.

Die Aufrufreihenfolge der registrierten Ereignisfunktionen hängt dabei von der Reihenfolge ihrer Registrierung ab.
Im folgenden Beispiel sind zwei unabhängige Komponenten "A" und "B" realisiert:

// +++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Prozedur "Component"                              +
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
@A+
@C+
@I:SysEvtInc // Ereignisverarbeitung einbinden
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Komponente A initialisieren                       +
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
sub ComponentAInit
(
  aWinDataList : handle; // DataList
)
{
  // Ereignis hinzufügen
  aWinDataList->Evt.Add(_WinEvtLstSelect,
    'Component:EvtLstSelectA');
  // weitere Initialisierungen
  // ...
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Komponente initialisieren                         +
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
sub ComponentBInit
(
  aWinDataList : handle; // DataList
)
{
  // Ereignis hinzufügen
  aWinDataList->Evt.Add(_WinEvtLstSelect,
    'Component:EvtLstSelectB');
  // weitere Initialisierungen
  // ...
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Komponente A terminieren                          +
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
sub ComponentATerm
(
  aWinDataList : handle; // DataList
)
{
  // Ereignis entfernen
  aWinDataList->Evt.Remove(_WinEvtLstSelect,
    'Component:EvtLstSelectA');
  // weitere Terminierungen
  // ...
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Komponente B terminieren                          +
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
sub ComponentBTerm
(
  aWinDataList : handle; // DataList
)
{
  // Ereignis entfernen
  aWinDataList->Evt.Remove(_WinEvtLstSelect,
    'Component:EvtLstSelectB');
  // weitere Terminierungen
  // ...
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Ereignis Komponente A                             +
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
sub EvtLstSelectA
(
  aEvt : event; // Ereignis
  aID  : int;   // Zeile
)
: logic; // ohne Bedeutung
{
  WinDialogBox(0, 'Komponente A',
    'Zeile ' + CnvAI(aID) + ' selektiert.',
    _WinIcoInformation, _WinDialogOK, 1);
  // Verarbeitung
  // ...
  return(true);
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Ereignis Komponente B                             +
// +++++++++++++++++++++++++++++++++++++++++++++++++++++
sub EvtLstSelectB
(
  aEvt : event; // Ereignis
  aID  : int;   // Zeile
)
: logic; // ohne Bedeutung
{
  WinDialogBox(0, 'Komponente B',
    'Zeile ' + CnvAI(aID) + ' selektiert.',
    _WinIcoInformation, _WinDialogOK, 1);
  // Verarbeitung
  // ...
  return(true);
}

Beide Komponenten verwenden ein DataList-Objekt und beide registrieren sich für das Ereignis EvtLstSelect.

Innerhalb der Applikation könnten die beiden Komponenten zum Beispiel wie folgt verwendet werden:

main
  local
  {
    tWinFrame : handle;
  }
{
  Evt.Init();
  tWinFrame # WinOpen('ComponentFrame', _WinOpenDialog);
  with ComponentFrame
  {
    $:dlData->WinLstDatLineAdd('1');
    $:dlData->WinLstDatLineAdd('2');
    $:dlData->WinLstDatLineAdd('3');
    $:dlData->WinLstDatLineAdd('4');
    // Komponenten initialisieren
    ComponentAInit($:dlData);
    ComponentBInit($:dlData);
    tWinFrame->WinDialogRun(_WinDialogCenterScreen);
    // Komponenten terminieren
    ComponentBTerm($:dlData);
    ComponentATerm($:dlData);
  }
  tWinFrame->WinClose();
  Evt.Term();
}

Durch die Reihenfolge der Initialisierung der Komponenten ergibt sich auch die Reihenfolge der Aufrufe der Ereignisfunktionen: Wird eine Zeile in dem DataList-Objekt selektiert, wird zuerst die Funtion EvtLstSelectA und anschließend die Funktion EvtLstSelectB aufgerufen.

Ich konnte mit diesem Verfahren bereits in mehreren Anwendungen die Erweiterbarkeit und Wartbarkeit von unabhängigen Applikationskomponenten gewährleisten beziehnungsweise verbessern. Und vielleicht haben Sie auch die ein oder andere Idee, für die diese Technik eine mögliche Lösung darstellt.

Download

CONZEPT 16-Modul "SysEvt" SysEvt-1.3.zip (6.60 KB)
Sie müssen angemeldet sein, um die Datei herunterladen zu können.

Klicken Sie hier, um die Nutzungsbedingungen für unseren Blog zu lesen.

2 Antworten

  1. Ich habe die Prozedur "SysEvt" im Download aktualisiert: Es sind jetzt auch die mit der Version 5.6 hinzugekommenen Ereignisse enthalten.

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Leave the field below empty!

Wünsche, Fragen oder Feedback sind willkommen:

Nutzungsbedingungen der Kommentarfunktion im Blog

1. Allgemeines

Vectorsoft AG („Anbieter“) stellt für Internetnutzer („Nutzer“) auf der Website
vectorsoft.de einen öffentlichen Blog bereit. Der öffentliche Blog dient dem
Informations- und Gedankenaustausch. Die Nutzer, welche sich mit Beiträgen und
Kommentaren beteiligen, verpflichten sich dazu, die Blog-Nutzungsbedingungen
einzuhalten und tragen die Verantwortung für die Richtigkeit und Angemessenheit
sowie Freiheit von Rechtsverletzungen ihrer Beiträge. Mit Nutzung der
Kommentarfunktion in unserem Blog akzeptieren Sie diese Nutzungsbedingungen.

2. Netiquette

Wir bitten Sie von persönlichen Angriffen und Provokationen aufgrund anderer
Meinungen abzusehen. Bitte argumentieren Sie sachlich und bewegen Sie sich auf
der Basis einer konstruktiven Diskussionskultur. Ihr Kommentar sollte stets im
Zusammenhang mit dem jeweiligen Thema sein, um Ausschweifungen in andere
Themenbereiche zu vermeiden. Das mehrmalige Posten desselben Kommentars
oder mehrerer ähnlicher Kommentare ist nicht erlaubt.

3. Verbot rechtswidriger Inhalte

Mit Absenden Ihres Kommentars bestätigen Sie, dass Sie keine Urheberrechte oder andere Rechte Dritter verletzen. Volksverhetzende, rassistische Äußerungen, Anleitungen zu Straftaten und deren Verherrlichung, Gewaltdarstellungen, pornografische Inhalte und Äußerungen, die Persönlichkeitsrechte verletzen sind untersagt.

4. Keine Werbung

Die Nutzung der Kommentarfunktion ist für kommerzielle oder parteipolitische
Zwecke nicht erlaubt. Werbliche Beiträge aller Art werden von uns umgehend
gelöscht.

5. Angaben zum Namen

Bei der Eingabe Ihres Namens achten Sie auf die zuvor genannten Grundsätze.

6. Quellenangaben

Bitte geben Sie bei der beabsichtigten Veröffentlichung von Zitaten oder Beiträgen
Dritter die jeweiligen Quellen an und erläutern dessen Bezug zum Blogbeitrag.

7. Verstoß gegen die Nutzungsbedingungen

Beiträge, die gegen diese Richtlinie verstoßen werden umgehend gelöscht. Sollten
Sie selbst Verstöße bemerken, so senden Sie uns bitte den Link des betreffenden
Kommentars per E-Mail an . Wir weisen ausdrücklich daraufhin, dass wir einzelne Nutzer bei wiederholten oder schweren Verstößen gegen diese
Nutzungsbedingungen ausschließen werden.

Stand: Sept. 2024

Deine Trial Version - jetzt anfordern!

Teste yeet - unverbindlich und kostenfrei

IHRE EVALUIERUNGSLIZENZ - JETZT ANFORDERN!

TESTEN SIE DIE CONZEPT 16 VOLLVERSION - UNVERBINDLICH und KOSTENFREI

Melden Sie sich bei unserem Newsletter an

Anrede*
     
Zustimmung zur Datenverarbeitung gem. DSGVO*



WordPress Cookie-Hinweis von Real Cookie Banner