![]() |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Dann lass doch den Setter bei Ergebnis weg und lass auch gleich fErgebnis weg und gebe bei GetErgebnis einfach die summe zurück.
|
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Du darfst dann auch nicht die Setter-Methoden direkt aufrufen, sondern müsstest die Properties setzen, welche dann wiederum in ihrem jeweiligen Setter die Berechnung durchführen können. Das kann auch durchaus sinnvoll sein, ich sehe da jetzt keinen Widerspruch zur OOP.
[edit] Zusammengefasst könnte das dann so aussehen:
Delphi-Quellcode:
[/edit]
TMeineDaten = class(TObject)
private fWert1 : Integer; fWert2 : Integer; procedure SetWert1(const Value: Integer); procedure SetWert2(const Value: Integer); function GetErgebniss(): Integer; public property Wert1 : Integer read FWert1 write SetWert1 Default 0; property Wert2 : Integer read FWert2 write SetWert2 Default 0; property Ergebnis : Integer read GetErgebnis; end; procedure TMeineDaten.SetWert1(const Value: Integer); begin FWert1 := Value; end; procedure TMeineDaten.SetWert2(const Value: Integer); begin FWert2 := Value; end; function TMeineDaten.GetErgebniss(): Integer; begin Result := fWert1 + fWert2; end; |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Ich würde allerdings ie Getter uns Setter protected machen, um jemendem, der die Klasse ableiten möchte, das Leben nicht unnötig kompliziert zu machen ;)
Ist aber nur eine klitzekleine Anregung, ich will ja keinen überfordern :stupid: |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
@DeddyH
bin begeistert von deinem Code. :) Also das sieht doch echt schlank und elegant aus. Ich würde nur gern das Ergebnis im Object storen, da er ja sonst bei jedem zugriff auf die Property diese Berechnung ausführt. Und das kann bei Komplexen sachen schon mächtig performance kosten. Also sprich die Funktion GetErgebniss soll intern Checken ob die Berechnung schon ausgeführt wurde, und das Ergebnis dann aus der Property fErgebnis holen, anstatt bei jedem zugriff nochmal zu berechnen. Aber ansonsten finde ich deinen Code top. :Thumbs up: mfG newbe |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Delphi-Quellcode:
Ist mir zu lang, dass jetzt zu erklären.
TMeineDaten = class(TObject)
private fWert1 : Integer; fWert2 : Integer; FErgebnis: Integer; FBerechnet: Boolean; procedure SetWert1(const Value: Integer); procedure SetWert2(const Value: Integer); function GetErgebniss(): Integer; public property Wert1 : Integer read FWert1 write SetWert1 Default 0; property Wert2 : Integer read FWert2 write SetWert2 Default 0; property Ergebnis : Integer read GetErgebnis; end; procedure TMeineDaten.SetWert1(const Value: Integer); begin FWert1 := Value; FBerechnet:=false; end; procedure TMeineDaten.SetWert2(const Value: Integer); begin FWert2 := Value; FBerechnet:=False; end; function TMeineDaten.GetErgebniss(): Integer; begin if not FBerechnet then begin FErgebnis:= fWert1 + fWert2; FBerechnet:=true; end; result:= FErgebnis; end; FBerechnet könnte man noch im constrcutor initialisieren. |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
@sirius
Genau so habe ich mir das vorgestellt. :) Eine letzte Frage hätte ich noch zu dem Themenkomplex. Unzwar zum constructor. Du weist darauf hin, das es wichtig wäre den Boolean zu initialisieren, was ja auch richtig ist. Jedoch verstehe ich eines nicht. Im Inet habe ich irgendwo aufgeschnappt, das man Klassenvariablen bzw. Felder immer erst nach abgeschlossener Object-Erstellung initialisieren sollte. Ich habe das so verstanden, das ich erst das Object erstellen soll und erst dann eine extra Init Prozedure aufrufen soll um Seiteneffekte zu vermeiden. Also in dieser Art.
Delphi-Quellcode:
Stimmt das den jetzt, oder ist da was wahres dran? Kann ich jede Art von Klassenvariable im Constructor initialisieren oderprocedure bla.init; begin Wert1 : Integer = 0; //Initialisieren Wert2 : Integer = 0; Ergebnis: Integer = 0; FBerechnet: Boolean = false; end; .... TForm1.buttonclick(Sender: TObject); var bla: TMeineDaten; begin bla:=TMeineDaten.create; bla.init; end; kann es da probleme geben weil die Objecterstellung ja im Constructor noch nicht abgeschlossen ist? mfG newbe |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Die Objekterstellung ist abgeschlossen, wenn du im constrcutor bist.
Der Code zum Erstellen der Instanz fügt der Compiler bei dem Wort "begin" des Constructors ein. Also, wie gesagt, direkt am Anfang. Edit: Vielleicht mal konkret. Jede Methode bekommt ja immer mindestens den Parameter "self" übergeben. Damit kannst du ja auf die Felder deiner Klasse zugreifen. Der Constructor bekommt zusätzlich noch einen Wert mitgegeben. Dieser sagt aus, ob der Constructor eine neue Instanz erstellen soll. Hier mal eine normale Methode
Delphi-Quellcode:
Und self zeigt einfach auf eine Art Record, in dem alle deiner Felder (Klassenvariablen) enthalten sind. Self ist dann auch das, was in deiner Objektinstanz "MeineDaten" (oder in Post #10: "test") steht. Ist halt einfach nur ein Zeiger auf deinen InstanzRecord. Und jede Instanz hat ihren eigenen Record.
//aus folgendem Code:
procedure TMeineDaten.SetWert1(const Value: Integer); begin FWert1 := Value; FBerechnet:=false; end; //wird eigentlich: procedure TMeineDaten.SetWert1(Self:Pointer; const Value: Integer); begin Self.FWert1 := Value; Self.FBerechnet:=false; end; So, und jetzt noch mal zum Constrcutor. Der hat, wie gesagt, neben "self" noch einen versteckten Parameter:
Delphi-Quellcode:
Was macht eigentlich _ClassCreate (neben Exceptionbehandlung und pipapo). Es reserviert einfach Speicher mittels new, wie bei einem normalen Record, den man dynamisch anlegt auch. Und dann wird die Adresse auf den Speicher zurückgegeben.
//aus folgendem Code:
Constructor TMeineDaten.Create; begin fBerechnet:=false; end; //wird dann: Constructor TMeineDaten.Create(Self:Pointer; doCreateClass:Boolean); begin if doCreateClass then begin Self:=_ClassCreate(Self, True); //Ab hier existiert dein Objekt. Result:=Self; end; Self.fBerechnet:=false; if DoCreateClass then _AfterConstruction(Self); end; So, und jetzt gibt es zwei Aufrufmöglichkeiten des Constructors:
Delphi-Quellcode:
Hier wird DoCreateClass auf True gesetzt und anstatt Self wird ein Zeiger auf die TypInformationen von TMeineDaten übergeben (also TMeineDatenClass oder einfach TClass)
test:=TMeindeDaten.create;
Wenn du jetzt den Constructor (irendwann nach der Instanzierung) nochmal so aufrufst (quasi, wie jede andere Methode auch):
Delphi-Quellcode:
dann ist DoCreateClass=False und an self wird eben der Wert von test übergeben (wie bei jeder anderen Methode auch).
test.create;
Nebenbei: Wenn jetzt test noch nicht instanziert wäre und du einfach test.create aufrufst (Was ein typischer Delphi-Anfängerfehler ist), wird für self eben nil (oder ein anderer krummer Wert) übergeben und DoCreateClass ist natürlich false. Dann greifst du hier auf den Record nil.fBerechnet zu, was eine Access Violation, meist in der Nähe von Addresse 0 = nil, auslöst. Allerdings ist es unüblich test.Create direkt aufzurufen. Der Zustand tritt eher ein, wenn man von TMeineDaten eine neue Klasse ableitet und dort, in einem neuen Constructor, dann inherited aufruft. Dann wird der Vorfahr, was TMeineDaten.Create ist, mit DoClassCreate=False aufgerufen. Ich hoffe ich habe nicht zu sehr verwirrt. ![]() Edit2: Erst die Klasse instanzieren und dann einen weiteren Befehl zur Initialisierung aufrufen ist in anderen Sprachen (die wir hier nicht erwähnen wollen) notwendig. In Delphi kannst du instanzieren und initialisieren in einem Abwasch, eben im constructor, machen. |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
@sirius
Vielen Dank an Dich für deine ausführliche Erklärung dazu. :) herzliche Grüße newbe |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
@All
Ich habe es jetzt so gemacht.
Delphi-Quellcode:
Erstmal die Frage ob das so OOP Konform durchgeht? Und dann hätte ich da noch eine Frage zur Eingabe-Exeptionbehandlung. Was wäre OOP Konform günstiger,
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Edit1: TEdit; Edit2: TEdit; Label1: TLabel; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; TMeineDaten = class(TObject) private fWert1 : Integer; fWert2 : Integer; FErgebnis: Integer; FBerechnet: Boolean; procedure SetWert1(const Value: Integer); procedure SetWert2(const Value: Integer); function GetErgebniss: Integer; public constructor create; property Wert1 : Integer read FWert1 write SetWert1; property Wert2 : Integer read FWert2 write SetWert2; property Ergebnis : Integer read GetErgebniss; end; var Form1: TForm1; implementation {$R *.dfm} { TMeineDaten } procedure TMeineDaten.SetWert1(const Value: Integer); begin if Value=5 then raise Exception.create('Wert 5 wird nicht als Eingabe akzeptiert!'); FWert1 := Value; FBerechnet := false; end; procedure TMeineDaten.SetWert2(const Value: Integer); begin if Value=5 then raise Exception.create('Wert 5 wird nicht als Eingabe akzeptiert!'); FWert2 := Value; FBerechnet := false; end; constructor TMeineDaten.create; begin FBerechnet := false; end; function TMeineDaten.GetErgebniss: Integer; begin if not FBerechnet then begin FErgebnis := fWert1 + fWert2; FBerechnet := true; end; result := FErgebnis; end; procedure TForm1.Button1Click(Sender: TObject); var test: TMeineDaten; begin test:=TMeineDaten.create; test.Wert1:=strtoint(edit1.text); test.Wert2:=strtoint(edit2.text); label1.caption:=inttostr(test.ergebnis); test.Free; end; end. die Exeptionbehandlung in die Klasse zu integrieren (im Setter) oder wie hier gehabt in einer Controlprocedure der VCL? Ich hätte die Exeptionbehandlung numal gerne komplett in der Klasse. So wie ich es jetzt mache, kann ich jedoch im Setter nicht prüfen, ob ein leeres Editfeld vorliegt. Delphi schmeist zwar eine Econvert Error Exeption wegen dem strtoint, jedoch hätte ich gerne eigene Exeptions und dann alle Bedingungsabfragen in der Klasse. Dazu müsste ich ja dem Setter ein String übergeben, die strtoint Konvertierung ausführen und dann aber einen Integer schreiben. Wäre solch eine vorgehensweise überhaupt Sinnvoll? Wie könntedafür die property Deklaration aussehen? Bei allem was ich probiert habe, beschwert sich Delphi wegen inkompatibler Typen. mfG newbe |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Wichtig für dich wäre noch try..finally. Das benutzt man wie folgt:
Delphi-Quellcode:
Ansonsten würdest du eine Exception werfen, das PRogramm springt raus aus deinen Methoden und du rufst nie Free auf -> Speicherloch
procedure TForm1.Button1Click(Sender: TObject);
var test: TMeineDaten; begin test:=TMeineDaten.create; try test.Wert1:=strtoint(edit1.text); test.Wert2:=strtoint(edit2.text); label1.caption:=inttostr(test.ergebnis); finally test.Free; //Der Teil wird immer ausgeführt, egal ob Exception kommt oder nicht end; end; Exceptions solltest du immer in den unteren Klassen werfen (so wie du es in TMeineDaten gemacht hast) und in der Klasse, welche sowieso für Anzeige (GUI) zuständig ist anzeigen. Die VCL macht das ja schonmal, in dem sie spätestens am Ende der Ereignis-/Messagebehandlung einen Except-Block hat und dann mittels Application.Showexception ein Fenster bringt. Wenn du also am Exceptiontest nichts verändern willst, dann kannst du es so durchlaufen lassen ohne eigene Exceptionbehandlung (try..except). Ansonsten kann man an dem Beispiel jetzt nicht viel mehr sagen. Ausser dass du in dem speziellen Fall anstatt inttostr auch tryintsotr nehmen kannst um Fehler gleich abzufangen bzw. eine eigene Exception zu kreieren. Eine übliche Vorgehensweise ist auch in bestimmten Klassen die Exception abzufangen und dann gleich wieder zu werfen, aber mit einer eigenen Ergänzung:
Delphi-Quellcode:
Und nicht zu vergessen auch mal eigene Exceptionklassen zu verwenden.
try
... except on e:Exception do raise Exception.create(e.MEssage+#13#10+'Ich will auch noch was sagen!'); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:34 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz