![]() |
Delphi-Version: 6
Objekt innerhalb Klasse nach außen hin "ReadOnly"
Hi!
Ich habe ein kleines Problem und würde mich sehr über etwas Hilfe freuen. Es geht dabei um die wie folgt aufgebaute Klasse:
Code:
So, nun mein Problem:
type
TMyKlasse = class(TObject) private FUnterObjekt: TUnterKlasse; ... public ... property UnterObjekt: TUnterKlasse read FUnterObjekt; end; Die Klasse TUnterKlasse enthält properties, die man "im normalen Gebrauch" (d.h. wenn sie als "eigenständiges" Objekt instanziert wird) schreiben darf. Das muss für meine Zwecke so sein. In diesem Fall allerdings, in dem UnterObjekt eine property von TMyKlasse ist, hätte ich es gerne so, dass sich sämtliche properties von FUnterObjekt wie ReadOnly verhalten. Optimalerweise soll auch verhindert werden, dass man irgendwelche Methoden von FUnterObjekt aufrufen kann. D.h. man soll hier von FUnterObjekt eigentlich wirklich nur Eigenschaften auslesen dürfen, sonst nichts. Geht das irgendwie? Beste Grüße! Robert PS (ganz andere Frage): Fallen constructor und destructor eigentlich auch unter den Oberbegriff "Methode"? |
AW: Objekt innerhalb Klasse nach außen hin "ReadOnly"
Ich glaube nicht, dass das geht, da du eigentlich nur einen Pointer auf ReadOnly gesetzt hast, denn die Property UnterObjekt enthält ja lediglich einen Zeiger auf die Klasse, die irgendwo im Speicher liegt.
Eine Idee für dein Konzept: Warum kapselst du das Objekt nicht vollständig und bietest nach außen nur Getter-Methoden (oder auch als Properties) an?
Delphi-Quellcode:
type
TUnterKlasse = class(...) private ... public property A : String read FA write FA; property B : String read FB write FB; property C : String read FC write FC; end; TMyKlasse = class(TObject) private FUnterObjekt: TUnterKlasse; ... public ... //property UnterObjekt: TUnterKlasse read FUnterObjekt; // als public getter function GetUnterObjectA(): String; function GetUnterObjectB(): String; function GetUnterObjectC(): String; // oder als Properties, dann kannst du die Getter-Methoden // aber private setzen property UnterObjectA : String read GetUnterObjectA; property UnterObjectB : String read GetUnterObjectB; property UnterObjectC : String read GetUnterObjectC; end; |
AW: Objekt innerhalb Klasse nach außen hin "ReadOnly"
Guter Denkanstoß!
Ich denke, ich werde eine THilfsKlasse einführen, die sämtliche Getter (bzw. ReadOnly-properties) und eine nicht auslesbare Referenz auf ein Objekt vom Typ TUnterKlasse (in diesem Fall FUnterObjekt) enthält. TMyKlasse bekommt dann ein FHilfsObjekt vom Typ THilfsKlasse spendiert und ich ändere die property UnterObjekt in FMyKlasse dahingehend, dass diese auf FHilfsObjekt verweist. Ist zwar ein bisschen um die Ecke, aber sollte funktionieren... Vielen Dank und Gruß! Robert |
AW: Objekt innerhalb Klasse nach außen hin "ReadOnly"
Warum integrierst du es nicht direkt? Diese eine "Reader"-Klasse ist dann doch mehr oder weniger unnütz?
|
AW: Objekt innerhalb Klasse nach außen hin "ReadOnly"
Hmmm...
Wenn jetzt alerdings FUnterObjekt wiederum nicht nur Datentypen, sondern auch Objekte enthält, habe ich das gleiche Problem wieder - nur eine Ebene tiefer :gruebel: nehme aber an, dass es prinzipiell keine Lösung gibt, die genau meinen Bedürfnissen entspricht... Oder? :glaskugel: |
AW: Objekt innerhalb Klasse nach außen hin "ReadOnly"
Naja, falls ich weitere TMyKlasse2, TMyKlasse3, ... habe, die ebenfalls ein ReadOnly-Unterobjekt vom selben Typen haben, wäre die THilfsKlasse ja schon sinnvoll.
|
AW: Objekt innerhalb Klasse nach außen hin "ReadOnly"
Hatte nicht vermutet, dass das Problem so weitläufig ist ;) Von daher kann so eine Reader-Klasse durchaus ihren Sinn erfüllen. Zur Not würde ich an der Stelle evtl. noch über RTTI nachdenken.
|
AW: Objekt innerhalb Klasse nach außen hin "ReadOnly"
was evtl auch noch eine Möglichkeit wäre, einfach ein Interface zu exportieren.
Hierbei kannst du genau angegeben, auf was zugreifbar ist. |
AW: Objekt innerhalb Klasse nach außen hin "ReadOnly"
Oder eine weitere Klasse (quasi so wie beim Interface), welche nur die gewünschten Propertry und das eine Objekt enthält.
Im Private/Protected-Abschnitt dann noch öffentlich ein Property zum enthaltenen Objekt. Wenn beide Klassen Die Kapsel-Klasse und deine Basisklasse in der selben Unit deklariert sind, dann kannstr du von deiner Klasse auch auf die privaten Sachen zugreifen und kommst so intern an alles ran. Von außen sieht aber jeder nur das ReadOnly-Zeugs. Ist das TUnterKlasse von dir geschreiben? Wenn ja, dann regel das über die Sichtbarkeiten und mach nur das Sichtbar, was auch sichtbar sein soll, woei es auch so ginge, wie z.B. bei TEdit (für dich) und TCustomEdit (öffentlich). |
AW: Objekt innerhalb Klasse nach außen hin "ReadOnly"
Zunächst mal vielen Dank an euch alle für die Hilfe!
Habe hier mal zwei mögliche Lösungen implementiert. Dier erste benutzt ein "Kapsel-Objekt" (namens ExpKlasseRO) innerhalb der OberKlasse, auf das der Benutzer zugreifen darf. Dieses liest alle Eigenschaften vom eigentlichen UnterObjekt ohne Schreibzugriff, wobei der User das eigentliche UnterObjekt gar nicht sieht. Das ist die Lösung, die auf Vorschlag von s.h.a.r.k. entstanden ist. Bitte dabei um Entschuldigung, aber hab alle drei Klassen (TOberKlasse, TExpKlasse, TExpKlasseRO) in ne eigene unit gepackt: PS: Die Namensgebung stimmt leider nicht mehr mit meiner ursprünglichen Frage überein. Was dort TMyKlasse war, ist jetzt TOberKlasse. Das einstige UnterObjekt vom Typ TUnterKlasse ist jetzt vom Typ TExpKlasse - was dem entpricht.
Delphi-Quellcode:
unit Unit1;
... implementation uses uTOberKlasse; {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var x: TOberKlasse; begin x := TOberKlasse.Create; {x.UnterObjektRO.EigenschaftRO := 10;} // geht natürlich nicht, soll ja auch ReadOnly sein Button1.Caption := IntToStr(x.UnterObjektRO.EigenschaftRO); FreeAndNil(x); end; end.
Delphi-Quellcode:
unit uTOberKlasse;
interface uses uTExpKlasse, uTExpKlasseRO; type TOberKlasse = class(TObject) private FUnterObjekt: TExpKlasse; FUnterObjektRO: TExpKlasseRO; public constructor Create; destructor Destroy; override; property UnterObjektRO: TExpKlasseRO read FUnterObjektRO; end; implementation uses SysUtils; constructor TOberKlasse.Create; begin inherited Create; FUnterObjekt := TExpKlasse.Create; FUnterObjektRO := TExpKlasseRO.Create(FUnterObjekt); end; destructor TOberKlasse.Destroy; begin FreeAndNil(FUnterObjektRO); FreeAndNil(FUnterObjekt); inherited Destroy; end; end.
Delphi-Quellcode:
unit uTExpKlasse;
interface type TExpKlasse = class(TObject) private FEigenschaft: Integer; procedure SetEigenschaft(AValue: Integer); function GetEigenschaft: Integer; public property Eigenschaft: Integer read GetEigenschaft write SetEigenschaft; end; implementation procedure TExpKlasse.SetEigenschaft(AValue: Integer); begin FEigenschaft := AValue; end; function TExpKlasse.GetEigenschaft: Integer; begin Result := FEigenschaft; end; end.
Delphi-Quellcode:
unit uTExpKlasseRO;
interface uses uTExpKlasse; type TExpKlasseRO = class(TObject) private FReferenzObjekt: TExpKlasse; function GetEigenschaftRO: Integer; public constructor Create(AReferenzObjekt: TExpKlasse); property EigenschaftRO: Integer read GetEigenschaftRO; end; implementation constructor TExpKlasseRO.Create(AReferenzObjekt: TExpKlasse); begin inherited Create; FReferenzObjekt := AReferenzObjekt; end; function TExpKlasseRO.GetEigenschaftRO: Integer; begin Result := FReferenzObjekt.Eigenschaft; end; end. Die zweite Lösung ist die mit dem Interface, auf Vorschlag von schlecki.
Delphi-Quellcode:
unit Unit1;
... implementation uses uTOberKlasse; {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var x: TOberKlasse; begin x := TOberKlasse.Create; {x.UnterObjektRO.Eigenschaft := 10;} // geht natürlich NICHT, weil bei UnterObjektRO vom Typ IExpInterface ist .Eigenschaft ReadOnly Button1.Caption := IntToStr(x.UnterObjektRO.Eigenschaft); FreeAndNil(x); end; end.
Delphi-Quellcode:
unit uTOberKlasse;
interface uses uTExpKlasse, uIExpInterface; type TOberKlasse = class(TObject) private FUnterObjekt: TExpKlasse; FInterfaceUnterObjekt: IExpInterface; public constructor Create; destructor Destroy; override; property UnterObjektRO: IExpInterface read FInterfaceUnterObjekt; end; implementation uses SysUtils; constructor TOberKlasse.Create; begin inherited Create; FUnterObjekt := TExpKlasse.Create; FInterfaceUnterObjekt := FUnterObjekt; end; destructor TOberKlasse.Destroy; begin // ACHTUNG! // entweder dies: FInterfaceUnterObjekt := nil; // ODER dies: {FreeAndNil(FUnterObjekt);} // siehe dazu z.B. http://development.mwcs.de/tutinterfaces.html // PS: Es entsteht KEIN Speicherleck! inherited Destroy; end; end.
Delphi-Quellcode:
unit uIExpInterface;
interface type IExpInterface = interface(IInterface) ['{5DD93564-1E6D-4D23-9EEE-B6E232CF4D9F}'] function GetEigenschaft: Integer; property Eigenschaft: Integer read GetEigenschaft; end; implementation end.
Delphi-Quellcode:
unit uTExpKlasse;
interface uses uIExpInterface; type TExpKlasse = class(TInterfacedObject, IExpInterface) private FEigenschaft: Integer; procedure SetEigenschaft(AValue: Integer); function GetEigenschaft: Integer; public property Eigenschaft: Integer read GetEigenschaft write SetEigenschaft; end; implementation procedure TExpKlasse.SetEigenschaft(AValue: Integer); begin FEigenschaft := AValue; end; function TExpKlasse.GetEigenschaft: Integer; begin Result := FEigenschaft; end; end. In jedem Fall ist es der OberKlasse möglich, direkt auf UnterObjekt zuzugreifen und alle beliebigen Schreiboperationen durchzuführen, während der Benutzer, der ein Objekt vom Typ TOberKlasse verwendet, nur die gewünschten Eigenschaften von UnterObjekt innerhalb des OberObjekt auslesen kann, ohne Schreibzugriff. Die erste Variante ist auch geeignet, wenn es sich bei UnterKlasse um eine Klasse handelt, die man nicht selbst implementiert hat (vgl. Anmerkung von himitsu). Hoffe, das hilft auch anderen weiter. Weitere Optimierungsvorschläge sind gerne erwünscht :wink: Beste Grüße! Robert |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05: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-2025 by Thomas Breitkreuz