![]() |
kleines OOP Beispiel bitte um Anmerk./Verbesserungvorschläge
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Delphipraxis Community,
Ich bin ein Delphi-Neuling und habe mal ein kleines ganz einfaches Übungsproject erstellt. Ich würde mich freuen, wenn hier mal ein paar erfahrenere Leute mal auf Fehler, oder Verbesserungmöglichkeiten prüfen könnten. Mir geht es vorallem um das Prinzip der Datenkapselung. Eventuell könnt ihr mir aber auch noch andere Hinweise zum Codedesign geben. Wie würdet ihr diees Beispiel elegant umsetzten? Für alle Hinweise bin ich dankbar. Was mich speziell noch Interessieren würde. Wozu benötigt man den Constructor/Destructor? Benötigt man ihn im diesem Beispiel überhaupt? Und wozu dient er sonst im allgemeinen? Was ist der Unterschied zwischen Constructor und einer Klasse.init; procedure? Was bedeutet der "Default 0" Wert in der Property Deklaration?
Delphi-Quellcode:
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; procedure SetWert1(const Value: Integer); procedure SetWert2(const Value: Integer); procedure BerechneErgebnis(); procedure SetErgebniss(const Value: Integer); public constructor create; destructor destroy; property Wert1 : Integer read FWert1 write SetWert1 Default 0; property Wert2 : Integer read FWert2 write SetWert2 Default 0; property Ergebnis : Integer read FErgebnis write SetErgebniss Default 0; end; var Form1: TForm1; implementation {$R *.dfm} { TMeineDaten } procedure TMeineDaten.BerechneErgebnis(); begin SetErgebniss(fWert1+fWert2); end; constructor TMeineDaten.create; begin end; destructor TMeineDaten.destroy; begin end; procedure TMeineDaten.SetErgebniss(const Value: Integer); begin FErgebnis := Value; end; procedure TMeineDaten.SetWert1(const Value: Integer); begin FWert1 := Value; end; procedure TMeineDaten.SetWert2(const Value: Integer); begin FWert2 := Value; end; procedure TForm1.Button1Click(Sender: TObject); var test: TMeineDaten; begin test:=TMeineDaten.create; test.SetWert1(strtoint(edit1.text)); test.SetWert2(strtoint(edit2.text)); test.BerechneErgebnis(); label1.caption:=inttostr(test.ergebnis); test.Free; end; end. |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Hallo und Willkommen in der DP :dp:
bis auf den leeren Konstruktor/Destruktor und fehlende Ressourcen-Schutzblöcke (try-finally) habe ich nichts Auffälliges bemerkt. Destroy ist als virtuell deklariert und sollte daher mit override überschrieben werden. Und zumindest ein inherited sollte dann schon drinstehen. Ansonsten OK. |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
hi,
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Gruß Ansgar |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Zitat:
d.h. wenn du im Consttructor einen default-Wert setzt, kannst du das so kenntlich machen, damit nicht unnötige info in der dfm gespeichert wird. Evtl. dient es auch dazu, im Objekt-Inspector einen nicht-default-Wert fett zu markieren. |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Zitat:
|
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Zitat:
2. Prinzipiell benötigt man beide immer, weswegen der Urahne aller Klassen (TObject) beide bereits enthält. Du musst sie aber nicht wie in deinem Beispiel leer überschreiben, wenn du nicht selbst noch Werte/Felder in deiner Klasse (de)initialisieren willst/brauchst. Dort kann man sie getrost weg lassen, wodurch automatisch der Konstruktor/Destruktor der Elternklasse verwendet wird. 3. s.o. :) 4. Eine init Prozedur ist eine einfache Methode. Sie würde keinen Speicher anfordern, d.h. sie kann erst nach dem Konstruktor aufgerufen werden - wie jede andere Methode auch (ausgenommen Klassenmethoden). Die Namensgebung "init" ist dabei völlig egal. Es ist zudem im generellen eigentlich üblich Initialisierungen im Konstruktor vorzunehmen, und dafür nicht noch eine separat aufzurufende Methode anzulegen (es sei denn der Konstruktor ruft diese dann auf). 5. Damit legst du den Wert der Eigenschaft fest, den sie direkt nach Aufruf des Konstruktors hat. Unter Delphi werden Felder grundsätzlich mit 0 initialisiert, weshalb hier die explizite Angabe nicht nötig wäre. Sie tut aber auch nicht weh :). Default-Werte lassen sich übrigens nur für einfache Datentypen vorgeben, d.h. nicht für Klassen, Records und Arrays (da bin ich mir zumindest 99%ig sicher). Edit: Yay, sind dem roten Kasten satte 3 Beiträge durchgegangen :shock: |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Wenn du einen Constrcutor mit xyz:=TKlasse.create (create ist jetzt der constructor, was ja normalerweise in Delphi auch so ist) aufrufst, führt der Compiler zu Beginn (und auch am Ende) des Constructors noch etwas Code ein. Dieser hat die Aufgabe den Speicherplatz zu reservieren, der für alle deine Felder (Variablen in der Klasse) benötigt werden. Einen Zeiger auf den Speicherplatz bekommst du ja dann vom constructor zurück und Speicherst ihn in xyz.
Der Constructor verbindet quasi zwei Aufgaben:
Du kannst einen Constrcutor auch ganz normal als Methode aufrufen, über xyz.create. Dann wird ausschließlich der Code innerhalb des Constructors ausgeführt. Dann sollte aber xyz schon vorher initialisiert sein. Genauso ist es, wenn du einen Vorfahr-constructor mit inherited aufrufst. Der Destructor löscht dann übrigens die gesamten Felder wieder aus dem Speicher. Der macht das übrigens immer. Den kann man auch nicht als normale Methode verwenden. default ist eine Angabe, welche sich für published properties anbietet. Defaultwerte müssen nicht in der Ressource gespeichert. |
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Zitat:
|
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
Stimmt, fällt im Beispiel nur nicht auf, weil es in derselben Unit steht.
|
Re: kleines OOP Beispiel bitte um Anmerk./Verbesserungvorsch
@All erstmal Danke für eure Antworten. :)
@mjustin & DeddyH Ich habe die Procedur Berechne Ergebnis absichtlich als Privat Deklariert um die Sichtbarkeit zu limitieren und das OOP-Prinzip der Datenkapselung umzusetzen. Ich könnte die Procedure natürlich auch als Public deklarieren um beispielsweise aus einer anderen Unit darauf zugreifen zu können. Mir fällt nur kein Grund ein warum dies nötig sein sollte. Vielleicht kannst du da mal ein sinnvolles Beispiel bringen das mir zeigt für welche Anforderungen diese Umsetzung angebracht ist. Grundsätzlich hätte ich am liebsten intelligente Objecte. In diesem Fall strebe ich eine strickte Trennung von externen Usereingaben und internen Berechnungen an. Sprich ich würde auf die Procedure Berechne Ergebnis am liebsten komplett verzichten. Ich hätte es gern so, das wenn beide Werte eingegeben sind das Object selbständig addiert und das Ergebnis in der Property Ergebnis zu Verfügung stellt. Aber vielleicht habe ich das auch falsche Vorstelllungen und sowas ist mit OOP gar nicht machbar/Sinnvoll! Ich stelle mir das so vor. Achtung ungetestet. mfG newbe
Delphi-Quellcode:
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; procedure SetWert1(const Value: Integer); procedure SetWert2(const Value: Integer); function GetErgebniss() Integer; //Getter eingefügt procedure SetErgebniss(const Value: Integer); public constructor create; destructor destroy; property Wert1 : Integer read FWert1 write SetWert1 Default 0; property Wert2 : Integer read FWert2 write SetWert2 Default 0; property Ergebnis : Integer read GetErgebnis write SetErgebniss Default 0; //Getter eingefügt end; var Form1: TForm1; implementation {$R *.dfm} ungetestet! { TMeineDaten } function GetErgebniss() :Integer; begin SetErgebnis(fWert1+fWert2); //oder Setter weglassen und direkt fErgebnis:=fWert1+fWert2; end; procedure TMeineDaten.SetErgebniss(const Value: Integer); begin FErgebnis := Value; end; procedure TMeineDaten.SetWert1(const Value: Integer); begin FWert1 := Value; //Wertebereich checken end; procedure TMeineDaten.SetWert2(const Value: Integer); begin FWert2 := Value; //Wertebereich checken end; procedure TForm1.Button1Click(Sender: TObject); var test: TMeineDaten; begin test:=TMeineDaten.create; test.SetWert1(strtoint(edit1.text)); test.SetWert2(strtoint(edit2.text)); // weg damit -> test.BerechneErgebnis(); label1.caption:=inttostr(test.ergebnis); test.Free; end; end. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:20 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