Einzelnen Beitrag anzeigen

Rob09

Registriert seit: 14. Aug 2007
58 Beiträge
 
Delphi 6 Personal
 
#10

AW: Objekt innerhalb Klasse nach außen hin "ReadOnly"

  Alt 11. Apr 2011, 20:29
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

Geändert von Rob09 (12. Apr 2011 um 18:00 Uhr) Grund: Jetzt erst die [DELPHI]-Umgebung entdeckt ;-)
  Mit Zitat antworten Zitat