Hinweise zur Implementation von MVC mit DELPHI
Die allgemeine Beschreibung finden Sie unter MVC-Konzept. Den kompletten Quellcode unter den Links im Text, weitere Programmbeispiele unter Modellierung mit UML und downloads.
Alle Rahmenplanentwickler, die etwas auf sich halten, haben in den letzten Jahren die Behandlung des MVC-Konzepts in die Unterrichtspläne geschrieben. Was auch immer unter Behandlung verstanden wird, für unsere Schule hieß das schon immer, alle Programme (also auch die sogenannten kleinen) werden unter diesem Design entwickelt und geschrieben. Das bedeutet, daß die Implementierung der Einfachheit des Konzepts (Trenne Daten und ihre Repräsentation!) zu folgen hat und der Programmieraufwand niedrig gehalten werden muß.
Genauso einfach ist scheinbar die Programmieraufgabe: benötigt werden Mechanismen, die die Daten zwischen GUI und Model hin- und hertransportieren, wenn entsprechende Ereignisse aufgetreten sind. Dazu kommen in Frage:
Die Aufgabe / Beispiel
Ein Programm berechnet den B.M.I.-Faktor einer Person. Es hat eine Fachklasse TPerson und die GUI-Klasse TFensterFrm.
Der Button
updateModel schickt die Daten ans Model
updateView holt die Daten und aktualisiert den View
Abnehmen reduziert den Wert von Gewicht.
Bild 1
1.1 Manuelles Polling über GUI-Komponenten
Die Aktionen werden durch getrennte GUI-Komponenten realisiert, was bei den meisten Anwenderprogrammen angebracht ist.
Die Fachklasse TPerson hat nur die notwendigen Set- und Get-Methoden.
TPerson = class(TObject)
private
Name : string;
Groesse : real;
Gewicht : real;
public
...
procedure SetName (n : string);
function GetName : string;
...
Die GUI-Klasse übernimmt Control- und Viewaufgaben.
unit uFenster;
INTERFACE
// ======================================================================
uses
...
uPerson;
TFensterFrm = class(TForm)
GroesseLbl: TLabel;
...
procedure updModelBtnClick (Sender: TObject);
procedure updViewBtnClick(Sender: TObject);
procedure AbnehmBtnClick(Sender: TObject);
private
Person : TPerson; // --- Model PERSON
procedure Init;
procedure DatenAktualisieren; // -- hier der Datentransport
procedure MaskeAktualisieren;
end;
IMPLEMENTATION
// ======================================================================
....
Procedure TFensterFrm.DatenAktualisieren;
// ----------------------------------------------------------------------
// Eingaben aus den Editfeldern an das Model-Objekt übergeben
begin
Person.SetName (NameEdt.Text);
Person.SetGroesse (StrToFloat (GroesseEdt.Text));
Person.SetGewicht (StrToFloat (GewichtEdt.Text));
end;
procedure TFensterFrm.updModelBtnClick(Sender: TObject);
// ----------------------------------------------------------------------
// Ereignis starten
begin
DatenAktualisieren;
Init; // Eingaben im Fenster löschen
end;
procedure TFensterFrm.MaskeAktualisieren;
// ----------------------------------------------------------------------
// Objektdaten an die View-Komponenten übergeben
begin
NameEdt.Text := Person.GetName;
GroesseEdt.Text := FloatToStr (Person.GetGroesse);
GewichtEdt.Text := FloatToStr (Person.GetGewicht);
BmiEdt.Text := FloatToStr (Person.HatBMI);
end;
procedure TFensterFrm.updViewBtnClick(Sender: TObject);
// ----------------------------------------------------------------------
// Ereignis starten
begin
MaskeAktualisieren
end;
...
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
&nb[1] [2] 下一页
[系统软件]InstallShield Express for delphi制作安装程序定… [常用软件]InstallShield Express制作Delphi数据库安装程序
[Delphi程序]为什么选择Delphi.Net ? [Delphi程序]《关于VisiBroker For Delphi的使用》(4)
[Delphi程序]Delphi 程序员代码编写标准指南 [Delphi程序]转贴:Conversion to Delphi 6: Missing unit Pro…
[Delphi程序]Borland Delphi 9 的新特性 [Delphi程序]Delphi 键盘码表
[Delphi程序]Chuck Jazdzewski的离开意味着Delphi的终结吗? [Delphi程序]Delphi Access violations 问题的解决之道