AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Observer-Pattern

Ein Thema von oki · begonnen am 5. Sep 2006 · letzter Beitrag vom 5. Sep 2006
Antwort Antwort
Seite 1 von 2  1 2      
oki

Registriert seit: 30. Dez 2002
Ort: Brandshagen
1.819 Beiträge
 
Delphi 2007 Professional
 
#1

Observer-Pattern

  Alt 5. Sep 2006, 08:04
Hi,

ich habe in einem anderen Thread nach der Programmierung nachladbarer Module gefragt. Dort wurde mir das Thema Observer-Pattern nahe gelegt. Nun hab nach diesem Thema gegoogelt und auch ne Menge Theorie dazu gefunden. Das Prinzip ist mir dabei schon recht klar aufgegangen. In meiner Delphi-Hilfe ist davon aber nichts zu finden.

Ist das Thema Observer nun ausschließlichein Verfahren (Technologie ...) oder gibt es dafür fertige Basisklassen. Finde ich diese nur nicht weil ich noch mit Delphi 5 arbeite?

Gruß oki
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#2

Re: Observer-Pattern

  Alt 5. Sep 2006, 08:54
Hi,
du wirst in Delphi kein implementierstes Pattern finden. Besser gesagt du findest keine Basis für eigene Implementierungen.

Die Pattern bestehen immer aus den gleichen Teilen, einem Problem und einer Lösung. Dabei ist sowohl das Problem als auch dessen Lösung sehr abstrakt (und damit von jeglicher Programmiersprache gelöst).

Die Vorteile liegen aber darin, dass diese Lösungen nicht von ungefähr kommen (die Vorteile werden immer erklärt). Vorallem werden hier Missverständnissen vorgebeugt. Spricht man vom Observer-Pattern, so ist dieses wohldefiniert. In Folge dessen kann man nicht mehr so leicht an einander vorbei reden (man vergleiche es mit der Verwendung von 3 Zeichen Akronymen, da kommt es deutlich schneller zu Missverständnissen).

Pattern sind also nur Designentscheidungen, die sehr eindeutlg ein Problem lösen und beliebig kombiniert und implementiert werden können. Aber ein Observer unter Delphi löst halt das selbe Problem wie ein Observer in Java.

Gruß Der Unwissende
  Mit Zitat antworten Zitat
generic

Registriert seit: 24. Mär 2004
Ort: bei Hannover
2.415 Beiträge
 
Delphi XE5 Professional
 
#3

Re: Observer-Pattern

  Alt 5. Sep 2006, 08:57
das ist das grosse oberthema designpatterns.

der observerpattern ist nicht anderes als eine liste von zeigern auf funktionen welche durch einen methodenaufruf ausgeführt werden.

beliebig viele beobachter können sich in diese liste ein und aushängen. alle eingehängten werden durch den einen methodenaufruf ausgeführt.

in der delphi hilfe wirst du warscheinlich garnichts über das thema finden.
designpatterns sind einfach nur funktionen bzw. klassen welche untereinander agieren mit einheitlichen namen. es ist ein programmierstil.

in .net wird sowas mit "delegates" abgebildet.

in delphi32 wirst du nicht drum rum kommen dir eine eigene klasse zu programmieren welches die funktion übernimmt. diese kannst du dann in deine observable klasse einbauen (kompositum)
Coding BOTT - Video Tutorials rund um das Programmieren - https://www.youtube.com/@codingbott
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#4

Re: Observer-Pattern

  Alt 5. Sep 2006, 09:09
Zitat von generic:
der observerpattern ist nicht anderes als eine liste von zeigern auf funktionen welche durch einen methodenaufruf ausgeführt werden.

beliebig viele beobachter können sich in diese liste ein und aushängen. alle eingehängten werden durch den einen methodenaufruf ausgeführt.
Sorry, aber da muss ich leider sagen, so stimmt das nicht. Was hier beschrieben wird ist nur eine mögliche Implementierung! Du kannst (kann sein dass ich das schon im letzten Thread wo das Thema aufkam schrieb) auch eine Liste von Objekten verwalten, die dann ein bestimmte Methode implementieren müssen.
Das Pattern an sich ist nur der Text, den du finden dürftest wenn du nach dem Observerpattern suchst. Ein Pattern ist wirklich nur die Beschreibung eines Problems und ein Designvorschlag für dessen Lösung. Die Implementierung kann sich sehr stark von Programmiersprache (und Programmierer) zu Programmiersprache (und Programmierer) unterscheiden.
So hättest du in C keine Möglichkeit eine Liste von Objekten zu verwalten (es gibt schließlich keine Objekte), in Java hingegen wäre es dir nicht möglich eine Liste von Zeigern zu verwalten (da es keine expliziten Zeiger gibt).
Trotzdem kannst du in beiden Sprachen das Observer Pattern verwenden und jeder wüßte was genau du machen möchtest (und einen Teil des Wie).

Zitat von generic:
designpatterns sind einfach nur funktionen bzw. klassen welche untereinander agieren mit einheitlichen namen. es ist ein programmierstil.
Stimmt wie gesagt so nicht. Designpatterns gehören imho auch nicht zum Programmierstil, wohl aber zum Softwaredesign. Es sind einfach nur Designentscheidungen um ein gewisses Ziel zu erreichen. Die wichtigsten Pattern (die bekanntesten) werden der Gang of Four (GoF) zugeschrieben. Diese zu kennen kann nie schaden (sie sind wirklich hilfreich). Wenn du dir diese anschaust, wirst du sicherlich früher oder später Teile davon in fremden Code wiedererkennen. Nicht immer ist jmd. klar, dass seine Implementierung auch einem Pattern entspricht, dennoch ist die häufig der Fall.

Ich denke auch über das Pro und Contra von Patterns findest du eine Menge bei Google.
  Mit Zitat antworten Zitat
oki

Registriert seit: 30. Dez 2002
Ort: Brandshagen
1.819 Beiträge
 
Delphi 2007 Professional
 
#5

Re: Observer-Pattern

  Alt 5. Sep 2006, 09:32
Hi Jungs (Mädels? )

o.k. im Großen und Ganzen verstanden. Trotzdem alles noch sehr abstrakt. somit die nächste Frage:

Sind die Observer so'ne Art Schnittstellen zum Rest meiner Umgebung oder kann ich jedes meiner eigenen Objecte beim Observable anmelden? Wenn ja, müssen die dann alle von der gleichen Observer-Basisklasse abstammen? Ich kann mir sonst nicht vorstellen, wie die ganze Sache mit der Übergabe des anmeldenden Observer beim Obsevable in der AddObserver-Methode funzt (Parametertyp). Ereignisse etc. dito.

gruß oki

P.S. zwischenzeitlich ist auch ein neuer Beitrag von dem unwissenden (verzeihe mir meine Wortspiele) rein gekommen, was meinem Beitrag imho keinen abbruch tut.
  Mit Zitat antworten Zitat
generic

Registriert seit: 24. Mär 2004
Ort: bei Hannover
2.415 Beiträge
 
Delphi XE5 Professional
 
#6

Re: Observer-Pattern

  Alt 5. Sep 2006, 09:47
man löst das überlicherweise mit interfaces. die vererbung nutzt man besser an anderen stellen.

damit du dir das besser vorstellen kannst:
die ereignisse in einen z.b. tbutton sind oberserver - allerdings mit der einschränkung kann jeweils nur einen geben.

eine funktion meldet sich deim observable an:
button.onclick:=meinefunkion; abmeldung:
button.onclick:=nil; "meinefunktion" muss dazu einen bestimmten typ erfüllen -> tnotifyevent

@Unwissende - ich versuche das einfach zu erklären. jemand der in den thema neu ist hat sonst viele viele schwierigkeiten mit den neuen begriffen. die bibel könnte ich auch beten:
Design Patterns. Elements of Reusable Object-Oriented Software. (Gebundene Ausgabe)

hier wären mögliche lösungen mit vererbung:
http://ods.schule.de/schulen/oszhdl/...hi/mvc.htm#obs
http://hsg.region-kaiserslautern.de/...rver/index.php
Coding BOTT - Video Tutorials rund um das Programmieren - https://www.youtube.com/@codingbott
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#7

Re: Observer-Pattern

  Alt 5. Sep 2006, 10:02
Hallo oki,

design patterns wie das observer pattern sind - zumindest seit der meisterlichen Identifizierung und Katalogisierung durch Erich Gamma e.a. - ein Erfolgsrezept für die objekt-orientierte Softwareerstellung. Eine direkte Lösung für dein Problem mit den nachladbaren Modulen findest du dort sicher nicht. Zuerst sind da wohl dynamische Montage-Lösungen wie Packages gefragt.

Grüße vom marabu
  Mit Zitat antworten Zitat
oki

Registriert seit: 30. Dez 2002
Ort: Brandshagen
1.819 Beiträge
 
Delphi 2007 Professional
 
#8

Re: Observer-Pattern

  Alt 5. Sep 2006, 10:14
Hi,

@generic: Super Dank. der Tip mit der Methodenzuweisung war gut. Ich seh immer mehr durch. Deine Links werd ich erst mal studieren. dann wird bestimmt noch ne Menge klarer für mich und ihr braucht nicht so viel Nachhilfe geben. Das wird vielleicht ein bischen dauern, aber ich lass die frage trotzdem offen. Ich steck ja noch mitten drin im Verstehen.

@marabu: Hast vollkommen Recht. Das thema mit den Modulen stell ich gerade erst mal zurück. Ich arbeite parallel an mehreren Sachen und das Thema Observer hilft mir aktuell auch weiter. Grundsätzlich halte ich es für gut dieses Thema zu beherrschen und seine Grenzen oder besser besonderen Einsatzgebiete zu kennen. so fallen mir später die entscheidungen leichter was an welcher Stelle geeigneter ist. Vom theorieansatz her scheint das Observerthema auch nicht so schwer zu sein. Ich hab es halt wohl schon einige male umgesetzt, aber nie aus dieser Sicht und so konsequent mit klar fundiertem design.


Gruß oki
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#9

Re: Observer-Pattern

  Alt 5. Sep 2006, 10:36
Wortspiel?

Deine aktuelle Frage ist das was die Pattern so interessant macht. Ein Pattern sagt dir nur, dass es eine solche Möglichkeit geben soll. Wie du diese umsetzt schreibt es nicht vor.
Es gibt in Delphi zwei Möglichkeiten, wie du das ganze machen kannst (mindestens). Beide wurden eigentlich schon von generic genannt.

Möglichkeit 1 besteht in der Verwendung eines Methodenzeigers. Einen solchen Zeiger kann man als eigenen Datentypen deklarieren und dann diesen Zeiger registrieren/deregistrieren.
Der Vorteil liegt klar darin, dass hier jede Methode registriert werden kann, die die gleiche Signatur verwendet. Dies ist aber auch gleichzeitig der Nachteil. An sich ist es der weniger OOP Weg. Die Objekt Orientierung versucht immer mit abstrakten Objekten zu arbeiten. Sicherlich ist ein Zeiger sehr sehr abstrakt, aber eben kein Objekt. Das heißt nicht, dass man den Weg nicht verwenden darf/sollte.
Trotzdem bleibt zu bedenken, dass man hier wirklich beliebigen Methoden erlaubt sich für die Benachrichtigung durch ein Ereignis zu registrieren. Das ist nicht unbedingt ein Pro für die Typsicherheit (oder Ähnliches).

Möglichkeit 2 besteht in der Verwendung des Kommandopatterns (wo du gleich siehst, dass sich Pattern super kombinieren lassen). Das Kommandopattern ist die Entsprechung eines Callbacks ohne Mehtoden-/Funktionszeiger. Hierbei wird die Verhaltensverbung in der OOP ausgenutzt. Hat eine Basisklasse A eine Method doFoo, so steht die auch allen Kinder B, C, ... und Kindeskindern (usw) zur Verfügung.
Um auch hier abstrakt zu bleiben wird als Basisklasse eine abstrakte Klasse verwendet. In Delphi entspricht dies einer Klasse mit einer abstrakten Methode. Alle Nachfahren müssen also diese Methode implementieren. Alternativ eignet sich auch ein Interface.
Der eigentliche Callback besteht jetzt darin, dass man konkrete Instanzen dieser Basisklasse hat (konkret in dem Sinne, dass die entsprechende Methode hier nicht abstrakt ist). Da man weiß, dass jeder Nachfahre der Basisklasse diese Methode implementieren muss, kann diese aufgerufen werden. Letztlich entspricht das in gewisser Weise natürlich wieder dem Prinzip der Methodenzeiger (aber implizit!).

Letzteres trifft man (imho) häufiger an, da es immer mehr Sprachen gibt, die Abstand von einer expliziten Zeigerarithmetik nehmen.

Deshalb möchte ich etwas mehr auf das 2te Beispiel eingehen:
Bei dem Observer Pattern gibt es zwei Klassen von Beteiligten. Einerseits die Observer (in beliebiger Anzahl). Dann gibt es noch ein einzelnes Objekt, das Observable. Die Observer beobachten das Observable. Soweit so klar.
Das Pattern geht hier aber etwas weniger intuitiv ran. Beobachten trifft es nicht ganz, vielmehr benachrichtigt das Observable die Observer über das Eintreten eines Ereignisses, für dass sie sich registriert haben. Nur registrierte Beobachter werden also über ein Ereignis informiert. Ein Observable kann dabei auch über mehr als ein Ereignis benachrichtigen, die Observer müssen sich dann auch für jedes Ereignis einzeln anmelden (Durchaus erwünscht, erspart unnötige Benachrichtigung von Observern die die Nachricht eh verwerfen).
Der Vorteil liegt hier klar auf der Hand, du kannst leicht etwas registrieren, was in einen Fernaufruf endet. Dein Objekt kann die Kapselung eines Vertreters sein, dessen Treiber sogar auf einer gänzlich anderen Plattform läuft (was zu hohen Kosten bei der Benachrichtigung führen kann, diese lassen sich durch die gezielte registrierung vermeiden). Das alles interessiert aber das beobachtete Objekt nicht.

Ja, werden wir nun etwas konkreter. Ich denke ein gutes Beispiel ist ein Editor. Dieses besteht aus einem Eingabefeld, dass warnehmen kann, dass jmd. etwas tippt. In Delphi könntest du also einfach von einem TMemo ausgehen. Das Ereingis onChange wird hier immer aufgerufen wenn sich der Text ändert. Ja, jetzt die Überleitung zum Observer. In Delphi hast du ja schon eine Möglichkeit dieses Ereignis zu beobachten. Du verwendest eben dieses Ereignis.
Dabei wird nichts anderes gemacht als der Methodenzeiger dieses Ereignis auf eine Methode gesetzt. Die IDE ermöglicht dir dabei auch gleich die zugehörige Methode zu erzeugen.
Jetzt sagen wir, du möchtest hier mehr als eine Sache machen, dann siehst du schnell wo das Problem an dieser Lösung liegt. Sagen wir einerseits möchtest du die Syntaxprüfen. Was du dabei machst ist erstmal egal. Du möchtest wissen ob die Syntax bei dem geänderten Text noch valide ist.
Andererseits möchtest du gerne, hm, automatische Zeilenumbrüche. Wenn die Zeile länger als 80 Zeichen ist, möchtest du das die an dieser Stelle umgebrochen wird.
Hast du nur einen Methodenzeiger ist das ganze schwer. Da du sauber arbeitest packst du die Syntaxprüfung und den Zeilenumbruch in je eine Klasse. Tritt das Ereignis ein, so wird von jeder Klasse eine Instanz in der Ereignisbehandlung verwendet um die jeweilige Aufgabe zu erfüllen. Problem nun, wie kannst du weitere Klassen hinzufügen für weitere Aufgaben? (Stichwort wäre hier Plugins). Diese sind dir nicht vorab bekannt, du kannst also nichts konkretes vorsehen. Natürlich kann es auch sein, dass du die Syntaxprüfung abschalten möchtest, da diese nur noch manuell ausgelöst werden soll.

Hier heißt die Lösung Observer-Pattern. Dieses gibt eine Lösung vor, in der sich Observer an- und abmelden können. Ob der Observer dabei ein Plugin ist oder nicht ist egal.
Dein TMemo ist hier das beobachete Objekt, das Observable. Ok, ein paar Kleinigkeiten fehlen noch, aber es wird halt das Observable (was ja klar ist).
Jetzt gilt es zu überlegen, was genau Beobachtet werden kann. Das OnChange Ereignis kannst du dabei aussen vor lassen. Wichtig ist, was sollen die Beobachter erfahren? Da sich hier der Inhalt des TMemo geändert hat und dieser ein TStrings ist, bietet es sich an diesen Inhalt zu übergeben. Wem der gehört und wo der herkommt ist der Syntaxprüfung egal. Die kann durch ein TStrings gehen und die Worte auf Validität prüfen. Analog arbeitet die Zeilenumbruchklasse.
Was du also brauchst ist eine Nachricht (nicht mit den Windowsnachrichten zu verwechseln!) die den Observern das geänderte TStrings-Objekt zur Verfügung stellt.

Dies kannst du in eine Abstrakte Basisklasse packen:
Delphi-Quellcode:
type
  TAbstractContentChangedListener = class(TObject)
    public
      OnContentChanged(const newContent : TStrings); virtual; abstract;
  end;
Dies ist deine abstrakte Basisklasse für alle Observer. Sowohl die Syntaxprüfung als auch der Zeilenumbruch müssen von dieser Klasse erben. Damit kannst du beide über die Änderung des Inhalts des Memos benachrichtigen. Den geänderten Inhalt (und damit das eigentliche Ereignis) bekommen sie als Argument.
Die Observer müssen jetzt also von dieser Klasse erben und die Methode auf ihre Weise implementieren. Wie sie dies tun ist deren Sache (Stichwort Abstraktion/Black-Box).

Was jetzt noch fehlt ist die Vervollständigung des Observables. Dieses muss ein Möglichkeit bieten, dass sich hier Observer registrieren und deregistrieren können und diese Observer auch benachrichtigen.
Das ist aber nun sehr einfach möglich. Es ist schließlich bekannt von welcher Basisklasse die Observer abstammen. Objekte von diesem Typ dürfen sich also registrieren/deregistrieren. Dazu werden sie irgendwie gespeichert (natürlich bietet sich eine Liste an, aber auch hier gibt es keine Einschränkungen).
Die eigentliche Benachrichtigung hat dann die Form, dass über die Liste iteriert wird und bei allen gespeicherten Objekten diese Methode mit dem veränderten Inhalt des TMemo aufgerufen wird.

Delphi-Quellcode:
type
  TObservableMemo = class(TMemo)
    private
      FContentChangeObserver : TObjectList; // irgendeine Möglichkeit zum Speichern
    protected
      procedure notifyContentChangeObserver;
    public
      procedure registerContentChangeObserver(const Observer : TAbstractContentChangeObserver);
      procedure deregisterContentChangeObserver(const Observer : TAbstractContentChangeObserver);
  end;
Soweit die Klasse. Was beim Registrieren / Deregistrieren gemacht wird ist klar. Letztlich hängt hier alles von der gewählten Implementierung ab. Im Fall einer TObjectList würde die Benachrichtung dann die folgende Form haben:
Delphi-Quellcode:
procedure TObservableMemo.notifyContentChangeObserver;
var i : Integer;
begin
  if self.FContentChangeObserver.Count > 0 then
  begin
    for i := 0 to self.FContentChangeObserver.Count - 1 do
    begin
      TAbstractContentChangeObserver(self.FContentChangeObserver[i]).onContentChanged(self.Lines);
    end;
  end;
end;
Ja, das war es auch schon. Die langen Namen sind dabei extra gewählt. Du kannst so auch dieses Memo noch um die Möglichkeiten erweitern über Tastendrücke oder Mausereignissse zu informieren. Ein Observable ist nicht nur auf ein Ereignis festgelegt. Ein Observer natürlich geanau so wenig. Möchtest mehr als ein Ereignis beobachten hast du aber das Problem, dass du nicht von mehr als einer Klasse erben kannst. Deshalb musst du dann an der Stelle auf Interfaces zurückgreifen und die sind unter Delphi nicht ganz so komfortabel wie in anderen Sprachen.


[ADD]
Ok, gerade lange geschrieben. Obwohl der Beitrag damit vielleicht schon überflüssig ist poste ich ihn trotzdem. Im Zweifel werden die Links trotzdem besser sein
[/ADD]
  Mit Zitat antworten Zitat
oki

Registriert seit: 30. Dez 2002
Ort: Brandshagen
1.819 Beiträge
 
Delphi 2007 Professional
 
#10

Re: Observer-Pattern

  Alt 5. Sep 2006, 11:04
Hi Unwissender (Wortspeile: Der_Unwissende -> vom Unwissenden -> der Unwissende hat ......... {na ja, vielleicht doch nicht so witzig})

erst mal mörder Dank für den langen Beitrag. Ich hab es auch gerade ob deiner Beispiele komplett verstanden und auch mit beiden Varianten (Ereignisse und abstrakte Methoden) Erfahrung. Mir ist jetzt aber definitiv klar, dass bei der Variante für abstrakte Methoden eine eigene Basisklasse notwendig ist. Damit sind alle anderen klassen und Objecte als Observer leider tabu.
somit scheint es Sinn zu machen in das Thema Intervaces rein zu schauen.

Nochmal größten Dank für deinen Beitrag

Gruß oki
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:16 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz