Delphi-PRAXiS
Seite 1 von 5  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   liege ich richtig mit dem OOP-Versuch (https://www.delphipraxis.net/191288-liege-ich-richtig-mit-dem-oop-versuch.html)

EdAdvokat 29. Dez 2016 16:54

Delphi-Version: 5

liege ich richtig mit dem OOP-Versuch
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen, ich bin in Fragen OOP noch nicht so sicher und bitte um eine Meinungsäußerung, ob ich mit einem kleinen Testprogramm richtig liege.
Es handelt sich um eine einfache Flächenberechnung als Beispiel. Mir geht es in erster Linie darum, ob ich die Getter und Setter sowie die propertys richtig
eingesetzt habe und ob man noch mehr in private verstecken könnte. Darauf würde ich dann aufbauen, um meine Möglichkeiten zu erweitern.
Ein Ok würde auch genügen. Danke

Der schöne Günther 29. Dez 2016 17:07

AW: liege ich richtig mit dem OOP-Versuch
 
Die Methoden auf welche die Properties zugreifen müssen nicht public sein, die können auch private oder protected sein.

Fritzew 29. Dez 2016 17:17

AW: liege ich richtig mit dem OOP-Versuch
 
Hallo

Es ist eine ganz schlechte Idee den Destructor Free zu nennen.
Free ist eine Methode von TObject die überprüft ob Self <> nil ist und dann den destructor Destroy aufruft.


Benenne Deinen Destructor um zu:
Interface

Delphi-Quellcode:
destructor Destroy; override;

Implementation

Delphi-Quellcode:
destructor TFlaecheninh.Destroy;
begin
  inherited Destroy;
end;
Dein Code ruft sich selber auf in Deinem destructor Free!!!

EdAdvokat 29. Dez 2016 17:44

AW: liege ich richtig mit dem OOP-Versuch
 
Danke für die schnellen Hinweise. Die Veränderung Destroy habe ich vorgenommen. Muss ich wirklich immer in derartigen Programmen einen destructor aufrufen?
Mehrfach habe ich gesehen, dass darauf verzichtet wurde. Wann und unter welchen Voraussetzungen muss ich den Speicher wirklich wieder frei geben?
Die Methoden, auf die die Propertys zugreifen (hier setLaenge, setBreite und GetFlaecheninhalt) lassen sich nicht in private oder protect verstecken.
Wie sollte ich also diese Methoden besser verstecken können ähnlich wie die private-Felder und Methoden FLaenge, FBreite, FFlaecheninhalt; function GetLaenge;
und function GetBreite?

EdAdvokat 29. Dez 2016 18:04

AW: liege ich richtig mit dem OOP-Versuch
 
Hallo Fritzew, in meinen Studien bin ich auf die Seite gestoßen: https://www.delphi-treff.de/object-p...n-und-objekte/
da wird u.a. zu Klassen und Objecte beispielhaft aufgeführt:

"...Beispiel: Eine Klassenmethode „simuliert“ eine Klassenvariable und zählt, wie viele Objekte es von einer Klasse gibt:
Delphi-Quellcode:
Unit Flaeche;

Interface

Type
  TFlaeche = class(TObject)
  private
  protected
    Function BerechneFlaeche: Double; virtual; abstract;
    Function BerechneUmfang: Double; virtual; abstract;
  public
    Constructor Create;
    Destructor Free;
    Class function count: Integer;
    Property Flaeche: Double read BerechneFlaeche;
    Property Umfang: Double read BerechneUmfang;
  End;

Implementation

Var anzahl: Integer;

Constructor TFlaeche.Create;
Begin
  Inc(anzahl);
End;

Destructor TFlaeche.Free;
Begin
  Dec(anzahl);
End;

Class Function TFlaeche.Count: Integer;
Begin
  result := anzahl;
End;

End.
Im Konstruktor (Create) wird die Anzahl erhöht, im Destruktor (Free) wieder herabgesetzt. Über die Klassenmethode Count (und natürlich über die globale Variable)
kann nun festgestellt werden, wie viele Instanzen es von TFlaeche gibt......"

Ich habe mich an diesem Beispiel orientiert, wohl falsch.
Hier wird mit dem Destructor TFlaeche.Count.Free gearbeitet.
Sollte man also immer "destructor ....Destroy" einsetzen?
Warum "override " was überschreibe ich da?

Der schöne Günther 29. Dez 2016 18:18

AW: liege ich richtig mit dem OOP-Versuch
 
Zitat:

Zitat von EdAdvokat (Beitrag 1357480)
Die Methoden, auf die die Propertys zugreifen (hier setLaenge, setBreite und GetFlaecheninhalt) lassen sich nicht in private oder protect verstecken.

Natürlich lassen sie sich das. Woran genau soll es scheitern?


Zitat:

Zitat von EdAdvokat (Beitrag 1357484)
Sollte man also immer "destructor ....Destroy" einsetzen?

Im Gegensatz zu anderen Sprachen hat der Destruktor in Delphi einen Namen. Man kann ihn nennen wie man will, sollte es aber wirklich nicht tun. Alle (bis auf dieses Tutorial) nennen ihn "destroy".

Der Grund weshalb man davon nicht abweichen sollte deckt sich mit deiner nächsten Frage

Zitat:

Zitat von EdAdvokat (Beitrag 1357484)
Warum "override " was überschreibe ich da?

Jede Klasse die du in Delphi definierst leitet sich implizit von der Ur-Klasse
Delphi-Quellcode:
TObject
ab. TObject hat einen Destruktor mit dem Namen "Destroy". Wenn ein Objekt deiner Klasse zerstört werden soll müssen alle Destruktoren die ganze Vererbungshierarchie hinauf abgearbeitet werden bis man bei TObject ankommt.

Der Destruktor von TObject ist "virtuell". Das bedeutet dass Unterklassen (z.B. deine) das Verhalten von "Destroy" abändern können. In deinem Fall zählt es die Klassenvariable "Anzahl" eins herunter damit man sieht dass es in der Welt nun eine Fläche weniger gibt. Doch hiernach muss im Destruktor noch "inherited" aufgerufen werden damit der Destruktor von TObject aufgerufen wird. Das fehlt in deinem Tutorial ebenfalls, das ist falsch.

Schau mal zu Themen wie "Vererbung" und "Polymorphie". Liest sich vielleicht beim ersten mal etwas wild, aber eigentlich ist es ganz einfach.


Als absolute Kurzfassung, so wäre das Tutorial korrekt:
Delphi-Quellcode:
interface

type
   TFläche = class // Man kann auch "TFläche = class(TObject)" schreiben
      public
         destructor Destroy(); override;
   end;
   

implementation

destructor TFläche.Destroy();
begin
   // Tue etwas
   inherited;
end;

TBx 29. Dez 2016 19:02

AW: liege ich richtig mit dem OOP-Versuch
 
Das Tutorial ist überarbeitungsbedürftig. Ich habe es auf meine ToDo-Liste gesetzt.

EdAdvokat 29. Dez 2016 21:05

AW: liege ich richtig mit dem OOP-Versuch
 
Danke für die Hinweise zum Destructor. Werde ich mir nochmals in Ruhe ansehen.
Warum sich bestimmte Methoden nicht verbergen lassen liegt im konkreten Fall daran, dass im Formular diese Methoden aufgerufen werden und wenn sie nicht
public sind, geht es nicht. Was könnte ich dagegen tun? Ich habe erkenntlich TForm in eine unit und TFlaecheninhalt in eine weitere unit gepackt. TForm-Methoden(Buttonclick...) greifen auf GetFlaecheninhalt beispielsweise zu :
Delphi-Quellcode:
procedure TForm1.BerechneFlClick(Sender: TObject);
begin
  Flaecheninh.setLaenge(strtoint(Laenge.text));
  Flaecheninh.setBreite(strtoint(Breite.text));
  LbFlaecheninhalt.Caption:=inttostr([B]Flaecheninh.GetFlaecheninhalt[/B]);
end;
Das ist mein kleines Problem. Oder muss ich damit leben?

TBx 29. Dez 2016 21:13

AW: liege ich richtig mit dem OOP-Versuch
 
Greif nicht auf die Methoden sondern auf das Property zu. Dafür ist das ja da.

Luckie 29. Dez 2016 21:55

AW: liege ich richtig mit dem OOP-Versuch
 
So hätte ich es gemacht:
Delphi-Quellcode:
Type
  TRechteck = class(TObject)
  private
    FLaenge: double;
   FBreite: double;
   FFlaeche: double;
   FUmfang: double;
    procedure BerechneFlaeche: Double;
    procedure BerechneUmfang: Double;
   procedure SetLaenge(laenge: double);
   procedure SetBreite(breite: double);
  public
   Property Laenge: Double write SetLaenge;
   Property Breite: Double write SetBreite;
    Property Flaeche: Double read FFlaeche;
    Property Umfang: Double read FUmfang;
  End;
 
  procedure TRechteck.SetLaenge(laenge: double);
  begin
    // ToDo:
   // wenn kleiner 0 -> Exception auslösen "Länge darf nicht kleiner 0 sein"
   // oder besser allgemeine Exception InvalideArgument
   laenge := FLaenge;
  end;
 
  procedure TRechteck.SetBreite(breite: double);
  begin
    // ToDo:
   // wenn kleiner 0 -> Exception auslösen "Breite darf nicht kleiner 0 sein"
   // oder besser allgemeine Exception InvalideArgument
   breite := FBreite;
  end;
 
  procedure TRechteck.BerechneFlaeche;
  begin
    FFlaeche := FLaenge * FBreite;
  end;
 
  procedure REechteck.BerechneUmfang;
  begin
    FUmfang := (2 * FLaenge) + (2 * FBreite);
  end;
 
///////////////////////////////////////////////////////////////////////////////

  procedure TForm1.BerechneFlClick(Sender: TObject);
  var
    TRechteck: Rechteck;
   Flaeche: double;
  begin
    Rechteck := TRechteck.Create;
   try
     // Eingaben validieren, wenn valid dann:
     Rechteck.Laenge := ...;
     Recheck.Breite := ...;
     Flaeche := Rechteck.Flaeche;
   finally
     Recheckt.Free;
   end;
  end;
Wozu der Zähler? Wenn jemand mehrere Flächen berechnen will, dann soll er das selbst implementieren. ;)

Aber du scheint das Prinzip der Objektorientierung noch nicht so ganz verstanden zu haben:
Delphi-Quellcode:
Type
  TFlaeche = class(TObject)
  private
  protected
    Function BerechneFlaeche: Double; virtual; abstract;
    Function BerechneUmfang: Double; virtual; abstract;
  public
Du willst anscheinen eine allgemeine Klasse schreiben, um Fläche und Umfang verschiedener geometrischer Körper zu berechnen. Und die Kind-Klassen sollen dann BerechneFlaeche und BerechneUmfang selbst implementieren. Idee gut. Aber Namensgebung schlecht. Die Klasse heißt TFlaeche. Warum berechnet eine Klasse TFlaeche den Umfang?

Delphi-Quellcode:
TGeometrischerKoerper = class(TObject)
Delphi-Quellcode:
TRechteck = class(TGeometrischerKoerper)
Delphi-Quellcode:
TDreieck = class(TGeometrischerKoerper)


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:39 Uhr.
Seite 1 von 5  1 23     Letzte »    

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