![]() |
Hilfklasse
Hoi, Sorry Betreff ist mir kein besserer eingefallen.
Es geht um eine Monsterklasse zu vereinfachen. Zum Beispiel (real ist anders)
Delphi-Quellcode:
Die implementiere Klasse hat da Getter die auf interne Daten zugreifen. Nun hätte ich das gerne so:
IMonster = interface
property ElementTyp: TTyp; //Kreis, Quadrat, etc. property ElementFarbe: TColor; property ElementGroesse: Double; ... property ReferenzTyp: TTyp; property ReferenzFarbe: TColor; property ReferenzGroesse: Double; ...
Delphi-Quellcode:
Damit könnte ich mir etliche Properties sparen.
IElement=interface
property Typ: TTyp; //Kreis, Quadrat, etc. property Farbe: TColor; property Groesse: Double; ... IMonster = interface property Element: IElement; property Referenz: IElement; Statt Monster.ReferenzFarbe schreibt man dann halt Monster.Referenz.Farbe. Aber wie implementiert man das dann? Klar: TElement = class(TInterfacedObject, IElement). Aber dann muss diese Klasse ja noch TMonster kennen. Oder es bekommt die Daten bei der Erzeugung mit. Dann muss die Klasse aber jedesmal neu erzeugt werden oder es braucht eine Benachrichtigung wenn sich die Daten ändern. Kann ich alles machen aber scheint mir recht aufwendig. (Nein - Datenhaltung in TElement kommt nicht in Frage) :gruebel: |
AW: Hilfklasse
Delphi-Quellcode:
constructor TMonster.Create;
begin ... FElement := TElement.Create(Self); //Übergabeparameter nach Lust und Laune benennen: Parent, Owner, Lieblingsonkel, Datengrab oder Mutti FReferenz := TElement.Create(Self); ... end; |
AW: Hilfklasse
Ich tue mich schwer das Beispiel zu verstehen. Element sind doch einfach nur Eigenschaften (Daten), keine Objekt, das etwas tut. Ich verstehe auch nicht, weshalb es TMonster/IMonster überhaupt kennen muss. Machen tut doch das Monster. Es guckt auf sein Feld
Delphi-Quellcode:
oder
Referenz
Delphi-Quellcode:
und handelt entsprechend.
Element
Geht es dir darum, in Monster direkt darauf zu reagieren, wenn man im Code z.B. sagt
Delphi-Quellcode:
? Dann würde man der Referenz im Konstruktor wohl einen Callback mitgeben den es aufrufen soll, wenn auf ihm was geändert wird. Oder es hat eine Event-Variable
meinMonster.Referenz.Farbe := blau
Delphi-Quellcode:
an die sich das Monster binden kann, um darauf zu reagieren dass in Referenz sich etwas geändert hat.
OnChange
Ein "Real World Example" ist wohl z.B.
Delphi-Quellcode:
. Da ist das auch so gelöst.
meinLabel.Font.Size := xx
Klingt kompliziert? Ist es auch. Ich finde das Overkill. Und das hängt mit diesem Property-Gefummel zusammen, gegen das ich nicht müde werde zu wettern, aber damit stehe ich hier im Delphi-Forum eher alleine da. Wie würde ich es machen?
Ja, statt
Delphi-Quellcode:
tippe ich jetzt
meinMonster.Referenz.Farbe := blau
Delphi-Quellcode:
Hebt sich aber auch schon wieder auf, wenn ich z.B. nicht nur Farbe, sondern auch Größe anpassen will. Ja, es sind ein paar Buchstaben mehr zu tippen wenn man was ändert. Aber an den anderen Stellen wird es so viel simpler: Die Daten sind an einem Platz, und sind wirklich nur Daten, und ich brauche keine Callbacks für Änderungen "eins weiter unten".
referenz := meinMonster.getReferenz();
referenz.farbe := blau; meinMonster.setReferenz(referenz); |
AW: Hilfklasse
Danke für alle Rückmeldungen und Anregungen.
@TiGü: Sowas habe ich befürchtet. Statt einem einfachen Zugriff muss ich dann im Getter auf den Parent, Owner, Monster ... zugreifen. Wird dann beim Debuggen etwas mühsamer. Aber vermutlich noch die beste Lösung. @Günther: Ich schrieb bereits: "Nein - Datenhaltung in TElement kommt nicht in Frage". Die Daten sind in TMonster und dort sogar nur über virtuelle Getter verfügbar. Wenn dann das TElement die Daten liefern soll, dann muss es auf TMonster zugreifen oder von dort die Daten bekommen. Das entspräche auch dem von Dir erwähnten Callback/Event/OnChange. Im Übrigen sind es wohl nur Lesezugriffe. |
AW: Hilfklasse
Den Owner braucht man nur, wenn die ParentComponent die SubKomponenten automatisch freigeben soll (ohne manuelles Free),
oder wenn die SubKomponenten auf die übergeordnete Komponente zugreifen müssen. (z.B. bei Zuweiseung Daten dort ändern oder Notifications/OnChangeEvents dort auslösen) Die Freigabe kann/wird hier über die Referenzzählung des Interfaces erledigt. (FElement ist ja ein IElement und kein TElement) |
AW: Hilfklasse
Wenn die Struktur des IMonster-Interface und die zugrunde liegenden Klassen nicht verändert werden können, bau eine Fassade, die deinem Anwendungsfall gerecht wird.
Delphi-Quellcode:
unit Fassade;
interface uses Graphics; type TTyp = (Kreis, Quadrat); IMonster = interface(IInterface) function GetElementTyp: TTyp; function GetElementFarbe: TColor; function GetElementGroesse: Double; function GetReferenzTyp: TTyp; function GetReferenzFarbe: TColor; function GetReferenzGroesse: Double; {...} property ElementTyp: TTyp read GetElementTyp; property ElementFarbe: TColor read GetElementFarbe; property ElementGroesse: Double read GetElementGroesse; {...} property ReferenzTyp: TTyp read GetReferenzTyp; property ReferenzFarbe: TColor read GetReferenzFarbe; property ReferenzGroesse: Double read GetReferenzGroesse; {...} end; IElement = interface(IInterface) function GetTyp: TTyp; function GetFarbe: TColor; function GetGroesse: Double; {...} property Typ: TTyp read GetTyp; property Farbe: TColor read GetFarbe; property Groesse: Double read GetGroesse; end; IMonsterFassade = interface(IInterface) function GetElement: IElement; function GetReferenz: IElement; {...} property Element: IElement read GetElement; property Referenz: IElement read GetReferenz; end; TMonsterReferenz = class(TInterfacedObject) constructor Create(AParent: IMonster); destructor Destroy; override; protected FParent: IMonster; end; TElement = class(TMonsterReferenz, IElement) function GetTyp: TTyp; function GetFarbe: TColor; function GetGroesse: Double; end; TReferenz = class(TMonsterReferenz, IElement) function GetTyp: TTyp; function GetFarbe: TColor; function GetGroesse: Double; end; TMonsterFassade = class(TMonsterReferenz, IMonsterFassade) constructor Create(AParent: IMonster); destructor Destroy; override; private FElement: IElement; FReferenz: IElement; public function GetElement: IElement; function GetReferenz: IElement; end; implementation { TMonsterReferenz } constructor TMonsterReferenz.Create(AParent: IMonster); begin inherited; FParent := IMonster; end; destructor TMonsterReferenz.Destroy; begin FParent := nil; inherited; end; { TElement } function TElement.GetFarbe: TColor; begin Result := FParent.GetElementFarbe end; function TElement.GetGroesse: Double; begin Result := FParent.GetElementGroesse; end; function TElement.GetTyp: TTyp; begin Result := FParent.GetElementTyp; end; { TReferenz } function TReferenz.GetFarbe: TColor; begin Result := FParent.GetReferenzFarbe end; function TReferenz.GetGroesse: Double; begin Result := FParent.GetReferenzGroesse; end; function TReferenz.GetTyp: TTyp; begin Restlt := FParent.GetReferenzTyp; end; { TMonsterFassade } constructor TMonsterFassade.Create(AParent: IMonster); begin inherited; FElement := TElement.Create(AParent); FReferenz := TReferenz.Create(AParent); end; destructor TMonsterFassade.Destroy; begin FElement := nil, FReferenz := nil, inherited; end; function TMonsterFassade.GetElement: IElement; begin Result := FElement; end; function TMonsterFassade.GetReferenz: IElement; begin Result := FReferenz; end; end. |
AW: Hilfklasse
Wenn die Getter schon passend in TMonster vorhanden sind, dann kannst du es ja auch mal so versuchen:
Delphi-Quellcode:
type
TTyp = (Kreis, Quadrat); type IElement = interface function GetFarbe: TColor; function GetGroesse: Double; function GetTyp: TTyp; property Typ: TTyp read GetTyp; property Farbe: TColor read GetFarbe; property Groesse: Double read GetGroesse; end; IReferenz = interface(IElement) end; IMonster = interface function GetElement: IElement; function GetReferenz: IReferenz; property Element: IElement read GetElement; property Referenz: IReferenz read GetReferenz; end; type TMonster = class(TInterfacedObject, IMonster, IElement, IReferenz) function IElement.GetFarbe = GetElementFarbe; function IElement.GetGroesse = GetElementGroesse; function IElement.GetTyp = GetElementTyp; function IReferenz.GetFarbe = GetReferenzFarbe; function IReferenz.GetGroesse = GetReferenzGroesse; function IReferenz.GetTyp = GetReferenzTyp; private function GetElement: IElement; function GetReferenz: IReferenz; function GetElementFarbe: TColor; function GetElementGroesse: Double; function GetElementTyp: TTyp; function GetReferenzFarbe: TColor; function GetReferenzGroesse: Double; function GetReferenzTyp: TTyp; end; { TMonster } function TMonster.GetElement: IElement; begin Result := Self as IElement; end; function TMonster.GetReferenz: IReferenz; begin Result := Self as IReferenz; end; |
AW: Hilfklasse
Hallo zusammen,
Danke nochmals für alle Vorschläge. Klar ist auf jeden Fall dass "nimm das Brett vor Deinem Kopf und machs einfach so" nicht geht. :cry: :-D Ich mach mich mal ran und versuche was so ähnlich wie Eure Vorschläge. Das IMonster-Interface und die zugrunde liegenden Klassen kann (und will) ich schon ändern, halt nur nicht so, dss die Daten nicht mehr von dort kommen. Vielleicht kann ich auf den Wrapper verzichten. Passieren muss auf jeden Fall was. :feuerchen: IMonster hat 95 properties, dazu noch viele Einzel-Methoden und noch Nachfahren die noch vieles zu nehmen. |
AW: Hilfklasse
Ich habe meinen Vorschlag nochmal überarbeitet. Das IReferenz Interface wird eigentlich nur für die Method Resolution Clause und in GetReferenz verwendet und muss somit gar nicht öffentlich sein.
Mit diesem Ansatz muss also nur die Implementierung entsprechend formuliert werden. Zusätzliche Hilfsklassen sind nicht notwendig.
Delphi-Quellcode:
type
TTyp = (Kreis, Quadrat); type IElement = interface function GetFarbe: TColor; function GetGroesse: Double; function GetTyp: TTyp; property Typ: TTyp read GetTyp; property Farbe: TColor read GetFarbe; property Groesse: Double read GetGroesse; end; IMonster = interface function GetElement: IElement; function GetReferenz: IElement; property Element: IElement read GetElement; property Referenz: IElement read GetReferenz; end;
Delphi-Quellcode:
type
IReferenz = interface(IElement) end; TMonster = class(TInterfacedObject, IMonster, IElement, IReferenz) function IElement.GetFarbe = GetElementFarbe; function IElement.GetGroesse = GetElementGroesse; function IElement.GetTyp = GetElementTyp; function IReferenz.GetFarbe = GetReferenzFarbe; function IReferenz.GetGroesse = GetReferenzGroesse; function IReferenz.GetTyp = GetReferenzTyp; private function GetElement: IElement; function GetReferenz: IElement; function GetElementFarbe: TColor; function GetElementGroesse: Double; function GetElementTyp: TTyp; function GetReferenzFarbe: TColor; function GetReferenzGroesse: Double; function GetReferenzTyp: TTyp; end; { TMonster } function TMonster.GetElement: IElement; begin Result := Self as IElement; end; function TMonster.GetReferenz: IElement; begin Result := Self as IReferenz; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:46 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 by Thomas Breitkreuz