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
Beste Grüße!
Robert