1.2 Manuelles Polling (halbautomatisch) über GUI-Komponenten
Wenn die Ausgabe von Ergebnissen und Daten unmittelbar nach der Eingabe erwünscht ist, kann man den Aufruf MaskeAktualisieren in die upDateModel-Komponente legen und auf die upDateView-Komponente verzichten. Der Rest bleibt gleich.
procedure TFensterFrm.updModelBtnClick(Sender:TObject); // ---------------------------------------------- // Ereignis starten begin DatenAktualisieren; Init; MaskeAktualisieren; end; | | Bild 2
| 2. Observer Pattern Design
Bild 3 - [Klicken Sie für den Quelltext auf die Klasse] Reichlich Aufwand, um eine Klasse Person zu observieren ... Durch die Auslagerung von Observer-Code in die Oberklasse bleibt dann aber nur der RunObservers-Aufruf in den Set-Methoden.
procedure TPerson.SetName (n : string); //---------------------------------------------- begin fName := n; fObserverMgr.RunObservers; // Message absenden end; | und im GUI
procedure TFensterFrm.FormShow(Sender: TObject); // --------------------------------------------- begin Person := TPerson.Create; Person.AddObserver(MaskeAktualisieren,self); end; | | Bild 4 Dem GUI ist ein zweiter View hinzugefügt, der vom Observer mit bedient wird.
|
|
3. Automatische Aktualisierung durch selbstgeschriebene Ereignisroutinen
Die Fachklasse hat außer den üblichen Set.. / Get-Methoden zusätzlich Code zur Ereignisbehandlung. Will man sicherstellen, daß die Änderung eines jeden Attributwertes verarbeitet wird, so braucht jede betreffende Methode die Variable OnChanged, die in der GUI-Klasse referenziert wird und die Aktualisierung anstößt.
Hier wird mit einem selbstdefinierten Typ TNotifyChange gearbeitet. Delphi stellt einen Typ TNotifyEvent zur Verfügung, der mit Properties ähnlich arbeitet. | Bild 5
|
unit uPerson; INTERFACE // ====================================================================== type TNotifyChange = procedure of object; // Deklaration eines Methodenzeigertyps TPerson = class(TObject) private Name : string; ... public OnChanged : TNotifyChange; // Vereinbarung einer ... // Referenzvariablen/Ereignismethode end;
IMPLEMENTATION // ====================================================================== ... procedure TPerson.SetGroesse (gr : real); (* ----------------------------------------- *) begin Groesse := gr; if assigned(OnChanged) // Ereignis auslösen then OnChanged; end;
procedure TPerson.Abnehmen; (* ----------------------------------------- *) begin Gewicht := Gewicht - 1; if assigned(OnChanged) // Ereignis auslösen then OnChanged; end;
... END. // ----- UNIT ------- |
In der GUI-Klasse sorgt die Methode Person.OnChanged in FormCreate dafür, daß bei jedem Event die GUI-Methode MaskeAktualisieren ausgeführt wird. Leider kann das in bestimmten Fällen zu Problemen führen. Editfelder, die sich gut für kombinierte Ein- und Ausgabe eignen, dürfen nicht für die Ausgabe von Rechenoperationen angesprochen werden; es sind also andere GUI-Komponenten dafür erforderlich. Die korrekte Initialisierung von Gewicht und Groesse mit 0 führt zu einer Exception wegen der unerlaubten Division durch Null bei Errechnung des BMI. Reine Textfelder sind unproblematisch.
unit uFenster;
INTERFACE // ====================================================================== uses ... uPerson;
type TFensterFrm = class(TForm) GroesseLbl : TLabel; ... procedure FormCreate (Sender: TObject); procedure updModelBtnClick (Sender: TObject); procedure AbnehmBtnClick (Sender: TObject); procedure EndeBtnClick (Sender: TObject);
private Person : TPerson; // --- Model PERSON procedure Init; procedure DatenAktualisieren; // --- hier der Datentransport procedure MaskeAktualisieren; public end;
var FensterFrm: TFensterFrm;
IMPLEMENTATION // ====================================================================== {$R *.DFM}
procedure TFensterFrm.FormCreate(Sender: TObject); // ---------------------------------------------------------------------- begin FensterFrm.Init; Person := TPerson.Create; Person.OnChanged := MaskeAktualisieren; // Methodenzeiger mit Methode end; // verknüpfen
... procedure TFensterFrm.DatenAktualisieren; // ---------------------------------------------------------------------- // wie vorher ... procedure TFensterFrm.updModelBtnClick(Sender: TObject); // ---------------------------------------------------------------------- begin DatenAktualisieren; end;
procedure TFensterFrm.MaskeAktualisieren; // ---------------------------------------------------------------------- begin NameEdt.Text := Person.GetName; BmiEdt.Text := FloatToStr(Person.HatBMI); end;
procedure TFensterFrm.AbnehmBtnClick(Sender: TObject); // ---------------------------------------------------------------------- begin Person.Abnehmen; end;
end. // ------ UNIT ------- |
Bewertung 1. Polling
Manuelles Polling (1.1. und 1.2) haben sich seit 10 Jahren im Unterricht bewährt und sind unaufwendig. An unserer Schule werden alle Programme, beginnend im Anfangsunterricht mit einer Fachklasse bis zu großen Projekten, in dieser Weise von den Schülern bearbeitet. Die Datenklassen sind frei von jeder technischen Erweiterung. Das erlaubt eine sehr einfache und klare OOA und Implementierung. 2. Observer Pattern Design
Viel Technik, wenig Erkenntnisgewinn (s.o.). Der Programmieraufwand pro observiertem Objekt ist so umfangreich, daß er sich für den Unterricht verbietet, wenn Schüler den kompletten Observer-Code schreiben sollten, zumal das durchaus nicht trivial ist. Eine Möglichkeit wäre, das ganze Paket als Bibliothek abzulegen. Bei dieser als auch der dritten Variante bleiben Fachklassen nicht von proprietärem Code frei, der sie mit dem Betriebssystem verknüpft, was einer Portierung im Wege steht. Der schöne Anspruch, das in Fachklassen auch nur Anwendungsdaten und Anwendungslogik enthalten sein sollen, ist dahin. 3. Selbstgeschriebene Ereignisroutinen
Die selbstgeschriebene Ereignissteuerung ist eher eine Bastlerlösung. TNotifyChange ist ein Prozedurtyp, ein ebenso mächtiges wie undurchsichtiges Konstrukt. Onchange eine Prozedurvariable, also gleichermaßen Attribut und Prozedur und damit proprietär belastet. Die o. g. Restriktionen und Fehler lassen Zweifel an einen routinemäßigen Einsatz im Unterricht aufkommen.
------------------- Literatur u. Links Hilfehandbuch Delphi 7 Amrhein, B.: Designpattern für Graphische Benutzeroberflächen http://www.hta-be.bfh.ch/~amrhein/Skripten/Swing/Pattern.pdf Höstklint, C.: Simple Observer Pattern http://www.delphi3000.com/member.asp?ID=9713 Paulus, H.: Das MVC-Konzept. (Schöne Präsentation) http://informatikag.bildung-rp.de/assets/download/D1-Paulus-Farben.pps
|