Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Code strukturieren! Wie macht man es richtig .. (https://www.delphipraxis.net/122145-code-strukturieren-wie-macht-man-es-richtig.html)

EWeiss 10. Okt 2008 06:45


Code strukturieren! Wie macht man es richtig ..
 
Eine grundsätzliche frage
Wie strukturiert man seinen Quelltext richtig.

Ich stelle fest das ich immer wieder in den alten trott von VB verfalle deshalb mal
diese frage um sicher sein zu können es direkt von vornherein richtig zu machen.

Ich lese eine zeile von einer Textdatei ein und übergebe diese wie folgt
Delphi-Quellcode:
zCAPTIONFONTHEIGHT(StrToInt(ParseThis(sBF, ',', 1)), 1);
Delphi-Quellcode:
function TSkinConfig.zCAPTIONFONTHEIGHT(N, RW : Integer): Integer;
begin
   if RW <> 0 then
    WasN := N;

  Result := WasN;

end;
Delphi-Quellcode:
TSkinConfig = class
private
 //
public
  function zCAPTIONFONTHEIGHT(N, RW : Integer): Integer;
end;
Den wert von zCAPTIONFONTHEIGHT lese ich so zurück!
Dafür habe ich in meiner SkinEngine Class eine extra Variable angelegt ebenfalls Public
Delphi-Quellcode:
function SK_CAPTIONFONTHEIGHT: Integer;
Die abfrage oder wenn ich den wert verändern will läuft wie folgt
Delphi-Quellcode:
function TSkinEngine.SK_CAPTIONFONTHEIGHT: Integer;
begin
   Result := SkinConfig.zCAPTIONFONTHEIGHT(0, 0);

end;
Wird ein neuer wert RW übergeben wird dieser in WasN gespeicher solange bis ein neuer übergeben wird..
Frage ich den wert ab wie angezeigt
Delphi-Quellcode:
SkinConfig.zCAPTIONFONTHEIGHT(0, 0);
bekomme ich als resultat den zuletzt übergeben Wert zurück geliefert.
Also in diesen Fall, den der aus meiner TextDatei eingelesen wurde.
Grundsätzlich funktioniert das aber mein bedenken es ist einfach nicht optimiert.
Da zu viel unnötiger Code geschrieben wird.

zu dem Thema noch eine zusätzliche Frage..
Was kommt nun genau unter Privat, Public, Published ?
Meine Frage deshalb damit ich nicht unötig langen Code abfragen muss..
So wie diesen hier.
Delphi-Quellcode:
SkinConfig.zAEROCOLOR(SkinEngine.zColorARGB(SkinEngine.zGetTrackValue(SkinEngine.zGetMainItem(ID_TRACK_OPACITY)),RGB(Red, Green, Blue)), WRITE);
Wie kann man sowas optimieren das man nicht immer SkinEngine davor schreiben muss.
Ich muss also immer zwischen SkinConfig und SkinEngine hin und her wandern und jedesmal den namen noch davor schreiben.
Wenn ich alles ohne Class mache kann ich aus jeder unit auf alle Funktionen zugreifen.
Denke aber das wäre auch nicht der richtige weg.

gruss Emil

mirage228 10. Okt 2008 07:24

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Zitat von EWeiss
Delphi-Quellcode:
SkinConfig.zAEROCOLOR(SkinEngine.zColorARGB(SkinEngine.zGetTrackValue(SkinEngine.zGetMainItem(ID_TRACK_OPACITY)),RGB(Red, Green, Blue)), WRITE);
Wie kann man sowas optimieren das man nicht immer SkinEngine davor schreiben muss.
Ich muss also immer zwischen SkinConfig und SkinEngine hin und her wandern und jedesmal den namen noch davor schreiben.

Wenns Dir wirklich nur um die Länge geht, sollte sich das so verkürzen lassen...
Delphi-Quellcode:
with SkinConfig, SkinEngine do
  zAEROCOLOR(zColorARGB(zGetTrackValue(zGetMainItem(ID_TRACK_OPACITY)), RGB(Red, Green, Blue)), WRITE);

Reinhardtinho 10. Okt 2008 07:36

Re: Code strukturieren! Wie macht man es richtig ..
 
Mal so nebenbei:

Zitat:

Zitat von EWeiss
Dafür habe ich in meiner SkinEngine Class eine extra Variable angelegt ebenfalls Public
Delphi-Quellcode:
function SK_CAPTIONFONTHEIGHT: Integer;

Das ist keine Variable, sondern eine Methode.

Zitat:

Zitat von EWeiss
Delphi-Quellcode:
 
  zAEROCOLOR(..)
  zColorARGB(..)
  zCAPTIONFONTHEIGHT(..)
  SK_CAPTIONFONTHEIGHT(..)

Diese Namen für Methode halte ich für sehr verwirrend, die Zusammensetzung deutet nicht darauf hin, dass es Methoden sind, auf den ersten Blick sehen sie aus wie Variablen. Beschreibe doch einfach was diese Methoden machen. Zum Beispiel:

GetAeroColor
SetAeroColor
AeroColorToFoo
...

EWeiss 10. Okt 2008 07:56

Re: Code strukturieren! Wie macht man es richtig ..
 
Mir ging es eigentlich um die Strukturierung des Quelltextes
Wie würdet ihr das denn anhand des beispiel machen ?

Irgendwie gehen wir am Thema vorbei.

gruss Emil

Luckie 10. Okt 2008 08:09

Re: Code strukturieren! Wie macht man es richtig ..
 
Ich denke, da gibt es kein richtig oder falsch. Es ist hauptsächlich eine Geschmaksfrage, wie man es selbst am besten findet und man es selbst am besten lesen kann. Wenn du damit klar kommst, würde ich da nichts ändern.

Aber was die Benennung der Methoden angeht, würde ich den Tipp von Reinhardtinho beherzigen. Hinzukommt die Großschreibung der Bezeichner. Nur Großbuchstaben wählt man eigentlich nur für Konstanten, deswegen würde mich die Art der Bezeichnung bei dir ziemlich verwirren. Methoden benannt man nach dem was sie machen, bestehen also meistens aus zumindest einem Verb. Die ersten Buchstaben der Wortbestandteile schreibt man dann groß, wie auch schon im Beispiel:
Delphi-Quellcode:
GetAeroColor
SetAeroColor
AeroColor
Die Methoden sind GetAeroColor und SetAeroColor und haben entsprechend ein verb vorangestellt. Get für die Getter und Set für die Setter. Bei der Eigenschaft fehlt dann dieses Verb.

Bei dir würde das dann entsprechend aussehen:
Delphi-Quellcode:
GetCaptionFontHeight // Getter
SetCaptionFontHeight // Setter
CaptionFontHeight // Property
Was soll eigentlich das kleine "z" vor den Methodennamen? Unter Delpjhi ist die Ungarische Notation eher nicht gebräuchlich, aufgrund der Typensicherheit der Sprache und der Codevervollständigung der IDE eigentlich auch überflüssig.

mikhal 10. Okt 2008 08:19

Re: Code strukturieren! Wie macht man es richtig ..
 
Schau dir mal die Style Guides an, die von Borland mal empfohlen wurden. In deutsch findest du hier eine entsprechende Zusammenstellung.

Grüße
Mikhal

EWeiss 10. Okt 2008 08:26

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Was soll eigentlich das kleine "z" vor den Methodennamen? Unter Delpjhi ist die Ungarische Notation eher nicht gebräuchlich, aufgrund der Typensicherheit der Sprache und der Codevervollständigung der IDE eigentlich auch überflüssig.
Jo stimmt schon ;)
Aber irgendwie komm ich damit nicht zurecht.
Es muss doch einen grund habe das ihr eure Classen anders aufbaut

Beispiel:
Delphi-Quellcode:
function TSkinConfig.zCAPTIONFONTHEIGHT(N, RW : Integer): Integer;
begin
   if RW <> 0 then
    WasN := N;

  Result := WasN;

end;
Könnte man ersetzen wenn ich so überlege mit

Delphi-Quellcode:
property CaptionFontHeight: Integer read FGetCaptionFontHeight write FSetCaptionFontHeight;
Theoretisch wäre das dass gleiche von der Funktionsweise.
Nur wo liegt der unterschied.
Ist es sinnvoller über property zu gehen oder über eine Funktion

gruss Emil

EWeiss 10. Okt 2008 08:29

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Zitat von mikhal
Schau dir mal die Style Guides an, die von Borland mal empfohlen wurden. In deutsch findest du hier eine entsprechende Zusammenstellung.

Grüße
Mikhal

Werd ich mal tun nur bei einer Diskussion bleibt mehr hängen als wenn ich das jetzt lese ..
Geht auch nur Online.

gruss Emil

Medium 10. Okt 2008 08:33

Re: Code strukturieren! Wie macht man es richtig ..
 
Es macht keinen all zu großen Unterschied. Properties sind ein sehr eleganter Weg das Geheimnisprinzip der OOP zu realiseren, und wie ich finde gerade in Delphi sehr angenehm implementiert. Getter/Setter Methoden ohne Properties würde ich in Delphi daher eher als nicht so schönen Stil ansehen, bei Sprachen die dieses Konstrukt nicht kennen sind sie halt der einzig sinnvolle Weg.
Das nette an Properties ist, dass man z.B. nur einen Weg (setzen/lesen) über eine Methode machen kann, und für den anderen Fall direkt auf die Variable verweist. Das spart in manchen Fällen einfach eine Methode die eh nur dem result den unveränderten Variableninhalt zuweisen würde.
Zudem werden vom Compiler für Properties noch zusätzliche RTTI Informationen erzeugt, die ab und an auch hilfreich sein können - aber das sind nun schon sehr spezielle Dinge.

Edith wollte den Hinweisen zur Benamsung nur noch ein wenig Nachdruck verleihen :)

Luckie 10. Okt 2008 09:00

Re: Code strukturieren! Wie macht man es richtig ..
 
Man kann entweder mit der Property direkt das private Attribut abfragen und setzen oder man kann über private Methoden, den sogenannten Gettern und Settern gehen. Mit einem Getter oder Setter hat man die Möglichkeit die Daten noch zu verifizieren bevor man sie den privaten ASttributen zuweist bzw. bevor man sie ausgibt. Deswegen wähle ich immer den Weg über die Getter und Setter, auch wenn ich sie eigentlich nicht bräuchte, aber eventuell braucht man sie ja doch noch mal.

Daniel 10. Okt 2008 09:05

Re: Code strukturieren! Wie macht man es richtig ..
 
Verifizieren kann man sie und man könnte ein Event auslösen - auch oft ein guter Grund wenigstens für Setter.

EWeiss 10. Okt 2008 09:23

Re: Code strukturieren! Wie macht man es richtig ..
 
Also würdet ihr lieber ein property verwenden anstelle der von mit gewählten funktion.
Zumindest hätte ich mir dann einiges an code gespart und muss nicht alles doppelt deklarieren.

Reicht dann diese eine property zeile oder muss ich zusätzlich noch Funktionen
einbauen mit dem ich den aktuellen status von FGetCaptionFontHeight erfrage ?
Nur dann hätte ich nichts gewonnen.

gruss Emil

DeddyH 10. Okt 2008 09:31

Re: Code strukturieren! Wie macht man es richtig ..
 
Bei einer Property hast Du mehrere Möglichkeiten:
Delphi-Quellcode:
private
  FBlubb: TBlubb;
...
public
  property Blubb: TBlubb read FBlubb write FBlubb;
Die einfachste: indirekter Zugriff auf das private Feld FBlubb sowohl lesend als auch schreibend.

Delphi-Quellcode:
private
  FBlubb: TBlubb;
  procedure SetBlubb(const Value: TBlubb);
...
public
  property Blubb: TBlubb read FBlubb write SetBlubb;
Lesender Zugriff immer noch indirekt, schreibender über einen Setter. Im Setter kann man Gültigkeitsprüfungen vornehmen und entsprechend reagieren.

Delphi-Quellcode:
private
  FBlubb: TBlubb;
  function GetBlubb: TBlubb;
  procedure SetBlubb(const Value: TBlubb);
...
public
  property Blubb: TBlubb read GetBlubb write SetBlubb;
Lesender Zugriff über den Getter, schreibender über den Setter. Im Sinne der OOP ist dies der "amtliche" Weg (gerade in der Hinsicht auf andere Sprachen als Delphi). Ich persönlich spare mir eine Getter-Methode aus Faulheitsgründen, da sie IMO keinen echten Mehrwert bringt.

[edit] Nachtrag: durch Weglassen von write bzw. read kannst Du eine Property zusätzlich noch als Read-/Write-Only definieren [/edit]

Daniel 10. Okt 2008 09:38

Re: Code strukturieren! Wie macht man es richtig ..
 
Eine Getter-Methode erlaubt Dir eine sog. "Lazy-Initialization".
Angenommen, Du hast "teure" Daten im Speicher, brauchst diese aber entweder nicht sofort oder aber nicht immer. Dann kann Dir eine Getter-Methode helfen, diese Daten erst dann zu holen / zu erzeugen, wenn sie tatsächlich benötigt werden.

DeddyH 10. Okt 2008 09:41

Re: Code strukturieren! Wie macht man es richtig ..
 
OK, das Argument kann ich gelten lassen.

Daniel 10. Okt 2008 09:43

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Zitat von DeddyH
OK, das Argument kann ich gelten lassen.

:kiss:
:mrgreen:

DeddyH 10. Okt 2008 09:44

Re: Code strukturieren! Wie macht man es richtig ..
 
Du bist sooo gut zu mir :oops: :mrgreen:

EWeiss 10. Okt 2008 10:45

Re: Code strukturieren! Wie macht man es richtig ..
 
Danke für eure Informationen werd dann auf property umsteigen bei einigen Funktionen
Das erparrt mir einiges an Tip arbeit.

Zumindest bei denen wo es nur um eine variable abspeichern/Lesen geht..

gruss Emil

Andreas H. 10. Okt 2008 11:55

Re: Code strukturieren! Wie macht man es richtig ..
 
Ja,

und die IDE unterstützt Dich Dabei auch noch. Einfach die Property definieren und über Klasse vervollständigen werden Getter und Setter automatisch eingefügt.

(edit: bei bds2006 jedenfalls :roll: )

EWeiss 10. Okt 2008 23:11

Re: Code strukturieren! Wie macht man es richtig ..
 
Warum funktioniert das nicht?
Was ist da Falsch

Delphi-Quellcode:
 property AeroEmulate[FGetAeroEmulate, FSetAeroEmulate: Integer]: Integer read FGetAeroEmulate write FSetAeroEmulate;
Also die Funktion als property
Delphi-Quellcode:
function TSkinConfig.zAEROEMULATE(nMode, RW : Integer): Integer;
begin
   if RW <> 0 then
    WasMode := nMode;

   Result := WasMode;

end;
gruss Emil

Neutral General 10. Okt 2008 23:35

Re: Code strukturieren! Wie macht man es richtig ..
 
Hi,

Ich verstehe grad leider nicht was du da tun willst :wiejetzt:

Allgemein:

Delphi-Quellcode:
property _Name_: _Datentyp_ read FVar write FVar;
Beispiel:

Delphi-Quellcode:
private
  FName: String;
public
  property Name: String read FName write FName;
end;
Vor privaten Variablen steht ein F.

oder:

Delphi-Quellcode:
property _Name_[Index: Integer]: _Datentyp_ read GetVar write SetVar;
Delphi-Quellcode:
private
  FWerte: Array of Integer;
public
  property Werte[Index: Integer]: Integer read GetWert write SetWert;
end;

implementation

function TKlasse.GetWert(Index: Integer): Integer;
begin
  Result := FWerte[Index];
end;

procedure TKlasse.SetWert(Index: Integer; const Value: Integer);
begin
  FWerte[Index] := Value;
end;
:arrow: Vor Getter/Setter-Methoden steht das Get/Set Prefix. Ohne F!

Du kannst Setter und Getter auf für Nicht-Array-Properties benutzen:

Delphi-Quellcode:
private
  FName: String;
  function GetName: String;
  procedure SetName(const Value: String);
public
  property Name: String read GetName write SetName;
end;

implementation

function TKlasse.GetName: String;
begin
  Result := FName;
end;

procedure TKlasse.SetName(const Value: String);
begin
  FName := Value;
end;
In den Getter- und Setter Methoden kannst du zudem beeinflussen, was genau zurückgegeben, (gelesen) und geschrieben wird. z.B.
Delphi-Quellcode:
function TKlasse.GetWert(Index: Integer): Integer;
begin
  if not (Index in [0..High(FWerte)]) then
    Result := -1
  else
    Result := FWerte[Index];
end;

procedure TKlasse.SetWert(Index: Integer; const Value: Integer);
begin
  if Value < 0 then
    FWerte[Index] := 0
  else
    FWerte[Index] := Value;
end;
Das hier sind jetzt nur Beispiele. Ist jetzt evtl nicht das allersinnvollste. Aber ich denke es verdeutlicht den Sinn und Zweck von Properties. Und auch deren Funktionsweise ;)

EWeiss 10. Okt 2008 23:55

Re: Code strukturieren! Wie macht man es richtig ..
 
Ich habe in meiner Funktion 2 Werte nicht einen
Beide möchte ich über properties zurücklesen geht das nicht?

Ich möchte nicht
Delphi-Quellcode:
if SkinEngine.AeroEmulate(0, 1) = 0
abfragen
sondern so wie bisher

Delphi-Quellcode:
if SkinEngine.AeroEmulate = 0
Du verstehst ?
Und das über eine property

Ich lese aus meiner Datei den wert
Delphi-Quellcode:
nMode : Integer
ein
ist RW > 0 wird dieser wert in WasMode gespeichert.
andernfalls behält WasMode den alten wert.

Delphi-Quellcode:
AeroEmulate(StrToInt(ParseThis(sBF, ',', 1)), 1);
ich kann also AeroEmulate gegenprüfen ohne den vorherigen wert zu löschen wenn RW
den wert von 0 hat.

gruss Emil

EWeiss 11. Okt 2008 00:38

Re: Code strukturieren! Wie macht man es richtig ..
 
So habs jetzt so gemacht ..
Ist aber vom Code her sogar noch mehr als über die alte Funktion.

Delphi-Quellcode:
  // SkinConfig
  TSkinConfig = class
  private
    FAeroEmulate : Integer;
    function GetAeroEmulate(FMode, FReadMode: Integer): Integer;
    procedure SetAeroEmulate(FMode, FReadMode: Integer; const Value: Integer);
  public
    property AeroEmulate[FMode, FReadMode: Integer]: Integer read GetAeroEmulate write SetAeroEmulate;
  end;
 
  function TSkinConfig.GetAeroEmulate(FMode, FReadMode: Integer): Integer;
  begin
     if FReadMode > 0 then
      FAeroEmulate := FMode;

     Result := FAeroEmulate;
  end;
 
  // aus meiner TextDatei eingelesen
  case SkinType of
    stAeroEmulate:
    begin
      AeroEmulate[StrToInt(ParseThis(sBF, ',', 1)), 1];
    end;
  end;
Delphi-Quellcode:
  // SkinEngine
  TSkinEngine = class
  private
    //
  public  
    function SK_AEROEMULATE: Integer;
  end;
 
  function TSkinEngine.SK_AEROEMULATE: Integer;
  begin
     Result := SkinConfig.AeroEmulate[0, 0];

  end;
 
  // im Code abgefragt
  if SK_AEROEMULATE > 0 then
  begin
    //
  end;
Und genau das meine ich extrem viel Code nur um eine Funktion abzufragen.

gruss Emil

Roachford 11. Okt 2008 01:17

Re: Code strukturieren! Wie macht man es richtig ..
 
Fällt dir nicht selber auf, dass du beim zweiten Aufruf der Funktion zwei sinnlose Parameter mitgeben musst, wo du doch nur einen Wert haben willst?

Und wo wir gerade mal so beim grübeln sind: kommt dir es nicht ein wenig komisch vor, dass Parameter für eine Bedingung sowie einen bedingungspezifischen Wert an eine Property gibst? Wird da nicht selbst ein wenige mulmig, wenn eine Property (ich übersetze nochmal explizit: Eigenschaft) eine Bedingung enthält, wann sie was übernimmt und die Bedingungsparameter ihr auch noch mitgegeben werden? Meinst du nicht auch, dass dieses lieber ausserhalb der Property gemacht werden sollte?

Delphi-Quellcode:
// SkinConfig
  TSkinConfig = class
  private
    fAeroEmulate : Integer;
  public
    function ReadConfig: boolean;

    property AeroEmulate: integer read fAeroEmulate write fAeroEmulate;
  end;
Delphi-Quellcode:
procedure TSkinConfig.ReadConfig;
begin
  // aus meiner TextDatei eingelesen
  case SkinType of
    stAeroEmulate:
      begin
        fAeroEmulate := StrToInt(ParseThis(sBF, ',', 1));
      end;

 ....
  end;
end;
Die Abfrage an sich ist schon hinfällig, da du fest 1 übergibst bei dem Aufruf. Und somit entscheidet allein der Case Zweig, ob die Variable zugewiesen wird oder nicht. Und da wir schon im spezifischen Case Zweig sind, ist die Abfrage sinnlos. Und da die Config eigentlich von der Klasse selbst eingelesen werden sollte, schliesslich hält sie die Config, kann sie direkt den Member setzen.

Und dein SkinEngine kann doch einfach nur die Instanz der TSkinConfig öffentlich anbieten und somit auch nutzen:

Delphi-Quellcode:
// SkinEngine
  ESkinException = class(Exception);
  ESkinConfigError = class(ESkinException);

  TSkinEngine = class
  private
    fConfig: TSkinConfig;

  public  
    constructor Create;
    destructor Destroy; override;

    property Config: TSkinConfig read fConfig; // kein write!!!
  end;
Delphi-Quellcode:
constructor TSkinEngine.Create;
begin
  inherited;

  fConfig := TSkinConfig.Create;

  if not fConfig.ReadConfig then
    raise ESkinConfigError.Create('Skin Config invalid or not available!');
end;

destructor TSkinEngine.Destroy;
begin
  fConfig.Free;

  inherited;
end;
Delphi-Quellcode:
  // im Code abgefragt
  if fConfig.AeroEmulate > 0 then
  begin
    //
  end;

EWeiss 11. Okt 2008 02:03

Re: Code strukturieren! Wie macht man es richtig ..
 
was ist da sinnlos?
Die beiden parameter sind berechtigt da es sich hier um eine nonvcl anwendung handelt.
Ich also auch innerhalb unabhängig von der Config die eigenschaften ändern kann .. muss

Delphi-Quellcode:
Result := SkinConfig.AeroEmulate[0, 0];
Result := SkinConfig.AeroEmulate[0, 0];
erste wert gibt das neue ergebnis zurück wenn der zweite auf 1 steht.
erste wert gibt das aktuelle(alte) ergebnis zurück wenn der abgefragte zweite wert = 0 ist.
Der zweite wert ist nichts anderes als ein schalter EIN oder AUS

verstehe nicht was da sinnlos ist.

Bei den anderen Punkten muss ich sagen nicht schlecht ;)
Werd das wohl in der art übernehmen..
Danke

gruss Emil

alzaimar 11. Okt 2008 09:38

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Zitat von EWeiss
verstehe nicht was da sinnlos ist.

Es ist keine Eigenschaft, sondern eine Prozedur. Der Getter setzt zudem die Eigenschaft, das ist "pfui, bäh" :zwinker: . Für einen Anwender der Klasse ist es nicht ersichtlich, das beim Lesezugriff bei bestimmten Kombination der Indexe (dazu sind die Parameter eigentlich gedacht) die darunterliegenden Daten verändert werden.

Auch schon in der prozeduralen Programmierung sind Funktionen, die nicht nur etwas liefern, sondern nebenbei auch verändernd wirken (=Seiteneffekte) ein absolutes 'No Go'. Eine Funktion (und nichts anderes ist ja eine Eigenschaft, auf die lesend zugegriffen wird) liefert Daten zurück, verändert aber keinesfalls die interne Semantik!
Natürlich kann man beim erstmaligen Lesezugriff ein Flag prüfen und ggf. setzen, um z.B. redundante langsame Abfragen zu vermeiden ("Fetch on Demand"), aber der Flag ist ja nicht Bestandteil der Semantik.
Delphi-Quellcode:
Function GetProperty : TSomeType;
Begin
  If Not FLoaded Then Begin
    FProperty := ExternalAndSlowReadProperty;
    FLoaded := True;
  End;
  Result := FProperty;
End;
Das ist ok, obwohl 'FLoaded' verändert wird.

In Deinem Fall würde ich eine zweite Eigenschaft 'AlternateAeroEmulate' definieren. Der Lesezugriff auf 'AeroEmulate' besitzt dann einen Parameter 'ReadMode', der steuert, ob FAlternateAeroEmulate' oder 'AeroEmulate' geliefert wird.

EWeiss 11. Okt 2008 15:47

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

In Deinem Fall würde ich eine zweite Eigenschaft 'AlternateAeroEmulate' definieren. Der Lesezugriff auf 'AeroEmulate' besitzt dann einen Parameter 'ReadMode', der steuert, ob FAlternateAeroEmulate' oder 'AeroEmulate' geliefert wird.
Da darf man sich nicht wundern warum heute 10GB für ein Spiel verschwendet werden
Wenn man für eine Aktion 5 Funktionen verwendet.
Die Gesellschaft ist schwer verschwenderisch geworden scheint überall der Fall zu sein
Selbst bei bit und byte

gruss Emil

jfheins 11. Okt 2008 15:59

Re: Code strukturieren! Wie macht man es richtig ..
 
Bei den heutigen Preisen von 10 cent je Gigabyte tendiert der Tradeoff zwischen Entwicklungskosten und Produktgröße eben immermehr dahin, dass die Entwicklung vereinfacht wird, und dafür das Ausgangsprodukt voluminöser wird ;)

.net Framework <> Assembler ;)

Es komt natürlich immer auf den Einsatzzweck an, auch heute gibt es noch Anwendungen, wo es auf die Größe ankommt. Nicht jeder will schließlich ein paar Gigabyte in einen Kühlschrank einbauen. Aber in Zeiten billiger Festplatten kann man eben dadurch enorm Entwicklungszeit (= -kosten) sparen ;)

alzaimar 11. Okt 2008 16:19

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Zitat von EWeiss
Da darf man sich nicht wundern warum heute 10GB für ein Spiel verschwendet werden
Wenn man für eine Aktion 5 Funktionen verwendet.

Zwei Emil, nur zwei. :zwinker:
Zitat:

Zitat von EWeiss
Die Gesellschaft ist schwer verschwenderisch geworden scheint überall der Fall zu sein..Selbst bei bit und byte

Es geht doch nicht um möglichst kompakten Code, sondern um klare Strukturen, gute Verständlichkeit, Robustheit und Erweiterbarkeit. Du entwickelst doch heute Anwendungen in einer Komplexität, die man sich vor 10/20 Jahren gar nicht vorstellen konnte. Um die Komplexität einigermaßen in den Griff zu bekommen, wurde OOP irgendwann als Heilsbringer angesehen. Immerhin bringt die Objektmetapher Ordnung in das(den? die?) Codewirrwarr. Das man dabei im Endeffekt 5-10x so viel Maschinencode produziert, muss man einfach in Kauf nehmen. Und ich spreche hier nicht von dazugelinkten Libraries, sondern einfach vom Overhead, den gut programmiertes OOP nun mal verursacht.

Ich schreibe lieber eine Zeile mehr, wenn es dem Verständnis dient. Beim Codieren geht es doch nicht darum, mit möglichst wenig Zeilen zum Ziel zu kommen, sondern eher darum, eine Problemlösung mit formalen Mitteln (=Programmiersprache, OOP) allgemeinverständlich zu formulieren.

Ein schönes und sonniges Wochenende!

EWeiss 11. Okt 2008 19:39

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Zwei Emil, nur zwei.
Also wenn du dir diesen link anschaust
http://www.delphipraxis.net/internal...=951802#951802

Dann habe ich jetzt schon bei weiten mehr an Code als über eine einfache Funktion
Gut muss aber sagen so bin ich auf der sicheren seite.

Addiere ich nun dein BEispiel hinzu sind es nicht nur zwei sondern
für jede abrage der Config * x
Das füllt ebend mal so die Seite locker mit mehr als 200 Zeilen.

Ich frage mich ob man dann noch eine übersicht behält.

Nur in der SkinConfig Unit habe ich jetzt schon 950 Zeilen.
In der uSkin schon 2440

gruss Emil

alzaimar 11. Okt 2008 19:44

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Zitat von EWeiss
Zitat:

Zwei Emil, nur zwei.
Also wenn du dir diesen Link anschaust...Dann habe ich jetzt schon bei weiten mehr an Code als über eine einfache Funktion

Aber dafür benötigst Du eine ganze Seite, um das zu erklären. Wenn Du kurzen, kompakten (sehr schwer lesbaren und fehleranfälligen) Code willst, verwende C(++).

EWeiss 12. Okt 2008 07:53

Re: Code strukturieren! Wie macht man es richtig ..
 
Hab jetzt ne neue Klasse angefangen..
Eine non VCL CheckBox

Was bietet sich da an, was man in create und destroy reinpacken kann?
Delphi-Quellcode:
unit uCheckButton;

interface
uses Windows, Classes, Messages;

type
  TSkinCheckButton = class
  private
    FButtonHandle: HWND;
    Img         : Cardinal;
    Style       : DWORD;
    UseState    : Integer;
  public
    constructor Create;
    destructor Destroy; override;
    function CheckButton(hOwner: HWND; FullpathImageName:PAnsiChar; stLabel: PAnsiChar;
      x, y, xW ,yH ,ButID: Integer; ARGBColor: COLORREF; StateMax: Integer): Integer;
    function GetCheckButtonStatus(hBut: DWORD): Integer;
    procedure SetCheckButtonStatus(hBut: DWORD; TrueFalse: Bool);
  end;

implementation
uses uSkin;

function TSkinCheckButton.CheckButton(hOwner: HWND; FullpathImageName,
  stLabel: PAnsiChar; x, y, xW, yH, ButID: Integer; ARGBColor: COLORREF;
  StateMax: Integer): Integer;
begin
    with SkinEngine do
    begin
      if RegisterButton(SKBUTIMAGE) <> 0 then
      begin
        // Erstelle ein GDIPLUS Image von Datei
        Img := AddResource((FullpathImageName));
        if Img <> 0 then
          Style := WS_CHILD or WS_VISIBLE or WS_TABSTOP or BS_AUTOCHECKBOX;
          FButtonHandle := CreateWindowEx(WS_EX_TRANSPARENT, SKBUTIMAGE, stLabel,
            Style, x, y, xW, yH, hOwner, ButID, sInstance, nil);
          if FButtonHandle <> 0 then
          begin
             if StateMax < 1 then StateMax := 2;
              // Speichere das Image Handle in die Property
              SetImageProperty(FButtonHandle, PROP_IMAGE, Img);
              SetImageProperty(FButtonHandle, PROP_STYLE, BS_AUTOCHECKBOX);
              SetImageProperty(FButtonHandle, PROP_TEXT_COLOR, ARGBColor);
              SetImageProperty(FButtonHandle, PROP_STATEMAX, StateMax);
             Result := FButtonHandle;
          end else
          begin
            // Lösche das Image
            DeleteResource(Img);
          end;
      end;
    end;

end;

constructor TSkinCheckButton.Create;
begin
  //
end;

destructor TSkinCheckButton.Destroy;
begin
  //

  inherited Destroy;
end;

// Hole den Checkbutton status
function TSkinCheckButton.GetCheckButtonStatus(hBut: DWORD): Integer;
begin
    Result := 0;

    if SendMessage(hBut, BM_GETCHECK, 0, 0) = BST_CHECKED then
       Result := -1;

end;

// Setze den Checkbutton status
procedure TSkinCheckButton.SetCheckButtonStatus(hBut: DWORD; TrueFalse: Bool);
begin
    if TrueFalse then
      UseState := BST_CHECKED
        else UseState := BST_UNCHECKED;

    SendMessage(hBut, BM_SETCHECK, UseState, 0);

end;

end.
Ja ich nerve ich weis :)
Hoffe die Namensgebung ist so in Ordnung!


gruss Emil

turboPASCAL 12. Okt 2008 08:21

Re: Code strukturieren! Wie macht man es richtig ..
 
Delphi-Quellcode:
unit uCheckButton;

interface

uses
  Windows,
  Messages;

//   Classes, // ?

type
  TSkinCheckButton = class
  private
    FButtonHandle: HWND;
    Img: Cardinal;
    Style: DWORD;
    UseState: Integer;
  public
    constructor Create(hOwner: HWND; FullpathImageName: PAnsiChar; stLabel: PAnsiChar;
      x, y, xW, yH, ButID: Integer; ARGBColor: COLORREF; StateMax: Integer);
    destructor Destroy; override;

    function GetCheckButtonStatus(hBut: DWORD): Integer;
    procedure SetCheckButtonStatus(hBut: DWORD; TrueFalse: Bool);
  end;

implementation

uses
  uSkin;

function TSkinCheckButton.Create(hOwner: HWND; FullpathImageName,
  stLabel: PAnsiChar; x, y, xW, yH, ButID: Integer; ARGBColor: COLORREF;
  StateMax: Integer);
begin
  with SkinEngine do
  begin
    if RegisterButton(SKBUTIMAGE) <> 0 then
    begin
        // Erstelle ein GDIPLUS Image von Datei
      Img := AddResource((FullpathImageName));
      if Img <> 0 then
        Style := WS_CHILD or WS_VISIBLE or WS_TABSTOP or BS_AUTOCHECKBOX;
      FButtonHandle := CreateWindowEx(WS_EX_TRANSPARENT, SKBUTIMAGE, stLabel,
        Style, x, y, xW, yH, hOwner, ButID, sInstance, nil);
      if FButtonHandle <> 0 then
      begin
        if StateMax < 1 then
          StateMax := 2;
              // Speichere das Image Handle in die Property
        SetImageProperty(FButtonHandle, PROP_IMAGE, Img);
        SetImageProperty(FButtonHandle, PROP_STYLE, BS_AUTOCHECKBOX);
        SetImageProperty(FButtonHandle, PROP_TEXT_COLOR, ARGBColor);
        SetImageProperty(FButtonHandle, PROP_STATEMAX, StateMax);
        Result := FButtonHandle;
      end
      else
      begin
            // Lösche das Image
        DeleteResource(Img);
      end;
    end;
  end;

end;

destructor TSkinCheckButton.Destroy;
begin
  UnRegisterButton(SKBUTIMAGE);
  DeleteResource(Img);
  DestroyWiindow(FButtonHandle);

  inherited Destroy;
end;

// Hole den Checkbutton status

function TSkinCheckButton.GetCheckButtonStatus(hBut: DWORD): Integer;
begin
  Result := 0;

  if SendMessage(hBut, BM_GETCHECK, 0, 0) = BST_CHECKED then
    Result := -1;

end;

// Setze den Checkbutton status

procedure TSkinCheckButton.SetCheckButtonStatus(hBut: DWORD; TrueFalse: Bool);
begin
  if TrueFalse then
    UseState := BST_CHECKED
  else
    UseState := BST_UNCHECKED;

  SendMessage(hBut, BM_SETCHECK, UseState, 0);

end;

end.

Vorschlag, frei Schanauzer.

EWeiss 12. Okt 2008 08:31

Re: Code strukturieren! Wie macht man es richtig ..
 
wäre eine idee aber wie sieht es bei den Create aus wenn du mehrere Checkboxen addierst ?
Wird dann nicht die alte gelöscht ?

oder kann man unbegrenzt Create aufrufen.
Danke für den Vorschlag

gruss Emil

Roachford 12. Okt 2008 11:01

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Zitat von EWeiss
wäre eine idee aber wie sieht es bei den Create aus wenn du mehrere Checkboxen addierst ?

Was meinst du mit "addieren"?

Der Constructor wird für jede neue Instanz durchlaufen. Wenn du nun eine neue Checkbox brauchst, lege dir eine neue Instanz an. Pro Instanz sind alle Felder der Klasse eindeutig (also jede Instanz hat für ihre Felder ihren eigenen Speicherplatz), ausser du deklarierst die Felder explizit als "class var".

Und auch würde ich den Status als property zusammenfassen:

Delphi-Quellcode:
   
  private
    function GetStatus: bool;
    procedure SetStatus(const AValue: bool);

  public
    ...
    property ButtonStatus: bool read GetStatus write SetStatus;
  end;

...

function TSkinCheckButton.GetStatus: bool;
begin
  Result := ( SendMessage(FButtonHandle, BM_GETCHECK, 0, 0) = BST_CHECKED );
end;

procedure TSkinCheckButton.SetStatus(const AValue: Bool);
const
  coStates: array[bool] of integer = (BST_UNCHECKED, BST_CHECKED);
begin
  SendMessage(FButtonHandle, BM_SETCHECK, coStates[AValue], 0);
end;
Um das nochmals zu verdeutlichen: Wenn du dir 2x diese Klasse anlegst, haben beide ihre eigenes FButtonHandle und somit auch jeweils ein eigenes Handle. Deshalb kann der Getter/Setter auch immer auf FButtonHandle zugreifen, da er das Handle der jeweiligen Instanz hat.

EWeiss 12. Okt 2008 11:53

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Was meinst du mit "addieren"?
Ich meine wenn ich die gleiche Klasse mehrfach aufrufe zum Beispiel
10 Checkboxen einbinde was passiert dann ?

Seltsamer weise gibt es ein AV wenn ich das versuche bei der zweiten Checkbox schon.

Danke für die Super infos werde davon verwenden was ich kann ;)

Nebenbei .. gehört zum selben projekt
Falls sich hier jeand mit PowerBasic auskennt
ich weiß nicht wie ich die zeilen nach Delphi rüberbringen soll :)

Delphi-Quellcode:
    pBits AS BYTE PTR

    CALL GetObject(hDIB, SIZEOF(bm), bm)
    pBits = bm.bmBits
    FOR P = (nWidth * nHeight) TO 1 STEP - 1
           @pBits[3] = A?
           @pBits[2] = R?
           @pBits[1] = G?
           @pBits[0] = B?
           pBits = pBits + 4
    NEXT
gruss Emil

Roachford 12. Okt 2008 12:02

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Zitat von EWeiss
Zitat:

Was meinst du mit "addieren"?
Ich meine wenn ich die gleiche Klasse mehrfach aufrufe zum Beispiel
10 Checkboxen einbinde was passiert dann ?

Seltsamer weise gibt es ein AV wenn ich das versuche bei der zweiten Checkbox schon.

Für jede CheckBox 1 Instanz anlegen! Löse dich von dem prozeduralem Design! Du hängst da noch vollkommen drinne. Ich denke du müsstest dir nochmal die Grundlagen des Objekt-orientierten-Programmierens anschauen, da ich hier grundlegende Verständnisprobleme sehe.

Delphi-Quellcode:
var
  lPixel: PRGBQuad;
  lBM: BITMAPHEADER; // oder BITMAPINFOHEADER - das weisst du selber besser...
  i: integer;
begin
  GetObject(hDIB, sizeof(lBM), lBM); // Rückgabewert beachten!

  lPixel := lBM.bmBits;

  for i := (nWidth*nHeight)-1 downto 0 do
  begin
    lPixel.rgbRed := R;
    lPixel.rgbGreen := G;
    lPixel.rgbBlue := B;
    lPixel.rgbReserved := A;

    Inc(lPixel);
  end;

EWeiss 12. Okt 2008 12:22

Re: Code strukturieren! Wie macht man es richtig ..
 
Danke für die übersetzung..
ja ich weiss hab da noch einige schwirigkeiten in Vb und konsorte gab es keine probleme damit.

Ich sende zwei Checkboxen hintereinander bei der zweiten krachts ;)
Na werd das schon noch geregelt bekommen.
Da kann mir keiner helfen ;)
Delphi-Quellcode:
hCtrl := CtrlCheckButton.CheckButton(hMain, PChar(SK_FOLDER + 'BTN_Check.png'),
  'AERO Blur mode', 60, 286, 130, 22, ID_AEROBLUR, SK_BTNTEXTCOLOR, 0);
SetAnchorMode(hCtrl, ANCHOR_CENTER_HORZ_BOTTOM);
SetZorder(hCtrl, HWND_TOP);


hCtrl := CtrlCheckButton.CheckButton(hMain, PChar(SK_FOLDER + 'BTN_Check.png'),
  'STANDARD mode', 60, 308, 130, 22, ID_AERODISABLE, SK_BTNTEXTCOLOR, 0);
SetCheckButtonStatus(hCtrl, TRUE);
SetAnchorMode(hCtrl, ANCHOR_CENTER_HORZ_BOTTOM);
SetZorder(hCtrl, HWND_TOP);
gruss Emil
Thanks für die Übersetzung :)

Roachford 12. Okt 2008 12:33

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Zitat von EWeiss
Ich sende zwei Checkboxen hintereinander bei der zweiten krachts

Hast du für CtrlCheckButton überhaupt eine Instanz angelegt? Hast du dazu irgendwo den Constructor aufgerufen? Und warum nimmst du ein und dieselber Instanz für 2 unterschiedliche CheckBoxen? Wozu dann die Member in der Klasse, wenn sie nur die Werte der letzten Checkbox enthalten?

TurboPascal hat dir nicht umsonst und sehr richtig als Änderung vorgeschlagen die CheckButton Methode zum Constructor umzuformen, also zu Create(). Und damit hättest du jedesmal eine richtige Instanz.

Bei deinem Code: Warum gibst du immer wieder hCtrl weiter (SetAnchorMode(), SetZorder())? Warum definierst du das nicht als Methoden von TSkinCheckButton?

Du übergibst selbst bei der SetCheckButtonStatus() immernoch die eigene Instanz. Wozu? Es ist eine Methode und braucht somit nichts übergeben zu bekommen, da sie eine Methode ist und sich somit nach den Membern richten kann.

Ich kann mich nur nochmal wiederholen: Les dir Grundlagenartikel zum OOP durch!

Wäre das nicht ein besser lesbarer Code?
Delphi-Quellcode:
CheckBox1 := TSkinCheckButton.Create(hMain, PChar(SK_FOLDER + 'BTN_Check.png'),
  'AERO Blur mode', 60, 286, 130, 22, ID_AEROBLUR, SK_BTNTEXTCOLOR, 0);
CheckBox1.SetAnchorMode(ANCHOR_CENTER_HORZ_BOTTOM);
CheckBox1.SetZorder(HWND_TOP);

CheckBox2 := CtrlCheckButton.CheckButton(hMain, PChar(SK_FOLDER + 'BTN_Check.png'),
  'STANDARD mode', 60, 308, 130, 22, ID_AERODISABLE, SK_BTNTEXTCOLOR, 0);
CheckBox2.ButtonStatus := true;
CheckBox2.SetAnchorMode(ANCHOR_CENTER_HORZ_BOTTOM);
CheckBox2.SetZorder(HWND_TOP);
Zitat:

Zitat von EWeiss
Da kann mir keiner helfen ;)

Und auch wenn ein Smiley hinter ist, bei solchen Sprüchen bekomm ich Ausschlag, schon allein da die Beantwortungsfrequenz in diesem Thread deutlich höher ist als in vielen anderen. Was willste noch mehr? Instant Resolution?

EWeiss 12. Okt 2008 12:40

Re: Code strukturieren! Wie macht man es richtig ..
 
Zitat:

Und auch wenn ein Smiley hinter ist, bei solchen Sprüchen bekomm ich Ausschlag, schon allein da die Beantwortungsfrequenz in diesem Thread deutlich höher ist als in vielen anderen. Was willste noch mehr? Instant Resolution?
Fühl dich doch nicht direkt angegriffen ich meinte damit das ohne den kompletten source zu veröffentlichen
jemand anderer nicht genau weis was da abläuft.

Nichts anderes habe ich damit aussagen wollen.

EDIT:
Zitat:

Hast du für CtrlCheckButton überhaupt eine Instanz angelegt? Hast du dazu irgendwo den Constructor aufgerufen? Und warum nimmst du ein und dieselber Instanz für 2 unterschiedliche CheckBoxen? Wozu dann die Member in der Klasse, wenn sie nur die Werte der letzten Checkbox enthalten?
hCtrl ist global definiert also wenn es neu aufgerufen wird ist das Handle gleich null
Bei dem erneuten aufruf wird ein neues Window für diese Checkbox erstellt erst dann geht es weiter in
der eigentlichen CheckButton Funktion.

gruss Emil


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:13 Uhr.
Seite 1 von 2  1 2      

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