Einzelnen Beitrag anzeigen

Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#3

AW: Klassenstruktur / Basisklasse -> Kindklassen => gleiche Datenbasis

  Alt 26. Jul 2012, 05:02
Verstehe ich das richtig, dass alle Klassen auf die gleiche Datenstruktur zugreifen und du willst, dass alle Änderungen synchron sind?

In dem Fall solltest du deine Klassenstruktur anders aufbauen – das, was aktuell deine Basisklasse ist, sollte eine unabhängige Dokument-Klasse sein. [edit]Oder du verwendest Interfaces, siehe unten.[/edit] Deine Aufgaben-Klassen können sich dann mit einer Instanz der Dokument-Klasse verbinden und auf deren Datenbestand zugreifen.

Beispiel:
Delphi-Quellcode:
TDocument = class
public
  function GetProperty(Identifier: string): Variant;
  procedure SetProperty(Identifier: string; Value: Variant);
end;

TTaskBase = class
protected
  FDocument: TDocument;
public
  constructor Create(Document: TDocument);
end;

TTaskAlpha = class(TTaskBase)
protected
  function GetPropertyA: Integer;
  procedure SetPropertyA(Value: Integer);
  function GetPropertyB: String;
  procedure SetPropertyB(Value: String);
public
  property PropertyA: Integer read GetPropertyA write SetPropertyA;
  property PropertyB: String read GetPropertyB write SetPropertyB;
end;

TTaskBeta = class(TTaskBase)
protected
  function GetPropertyA: Integer;
  procedure SetPropertyA(Value: Integer);
  function GetPropertyC: Boolean;
  procedure SetPropertyC(Value: Boolean);
public
  property PropertyA: Integer read GetPropertyA write SetPropertyA;
  property PropertyC: Boolean read GetPropertyC write SetPropertyC;
end;

implementation

constructor TTaskBase.Create(Document: TDocument);
begin
  inherited Create;
  FDocument := Document;
end;

function TTaskAlpha.GetPropertyA: Integer;
begin
  Result := FDocument.GetProperty('A');
end;
procedure TTaskAlpha.SetPropertyA(Value: Integer);
begin
  FDocument.SetProperty('A', Value);
end;

function TTaskAlpha.GetPropertyB: String;
begin
  Result := FDocument.GetProperty('B');
end;
procedure TTaskAlpha.SetPropertyB(Value: String);
begin
  FDocument.SetProperty('B', Value);
end;

function TTaskBeta.GetPropertyA: Integer;
begin
  Result := FDocument.GetProperty('A');
end;
procedure TTaskBeta.SetPropertyA(Value: Integer);
begin
  FDocument.SetProperty('A', Value);
end;

function TTaskBeta.GetPropertyC: Boolean;
begin
  Result := FDocument.GetProperty('C');
end;
procedure TTaskBeta.SetPropertyC(Value: Boolean);
begin
  FDocument.SetProperty('C', Value);
end;
Delphi-Quellcode:
var
  Document: TDocument;
  TaskAlpha: TTaskAlpha;
  TaskBeta: TTaskBeta;
begin
  Document := TDocument.Create(...);
  // * Document irgendwie initialisiert *

  TaskAlpha := TTaskAlpha.Create(Document);
  TaskBeta := TTaskBeta.Create(Document);

  // Property A ändert ihren Wert synchron:
  TaskAlpha.PropertyA := 42;
  writeln(TaskAlpha.PropertyA); // gibt 42 aus
  writeln(TaskBeta.PropertyA); // gibt 42 aus

  TaskBeta.PropertyA := 314;
  writeln(TaskAlpha.PropertyA); // gibt 314 aus
  writeln(TaskBeta.PropertyA); // gibt 314 aus

  // Diese Properties werden im Beispiel nur von jeweils einer Aufgabenklasse benutzt:
  TaskAlpha.PropertyB := 'Foo';
  TaskBeta.PropertyC := True;

Edit: Eine andere Variante wäre, mit Interfaces zu arbeiten – das entspräche eher deinem bisherigen Ansatz. Aber das geht natürlich nur, wenn deine Aufgabenklassen kein neues Verhalten (z.B. neue Methoden) einführen, sondern ausschließlich Untermengen der Mutterklasse bereitstellen (wobei die Klasse tendenziell zum God-Object mutieren könnte):
Delphi-Quellcode:
  ITaskAlpha = interface
    function GetPropertyA: Integer;
    procedure SetPropertyA(Value: Integer);
    function GetPropertyB: String;
    procedure SetPropertyB(Value: String);

    property PropertyA: integer read GetPropertyA write SetPropertyA;
    property PropertyB: string read GetPropertyB write SetPropertyB;
  end;

  ITaskBeta = interface
    function GetPropertyA: Integer;
    procedure SetPropertyA(Value: Integer);
    function GetPropertyC: Boolean;
    procedure SetPropertyC(Value: Boolean);

    property PropertyA: integer read GetPropertyA write SetPropertyA;
    property PropertyC: boolean read GetPropertyC write SetPropertyC;
  end;

  TDocument = class(TInterfacedObject, ITaskAlpha, ITaskBeta)
    function GetPropertyA: Integer;
    procedure SetPropertyA(Value: Integer);
    function GetPropertyB: String;
    procedure SetPropertyB(Value: String);
    function GetPropertyC: Boolean;
    procedure SetPropertyC(Value: Boolean);
  end;
Und dann so:
Delphi-Quellcode:
var
  Document: TDocument;
  TaskAlpha: ITaskAlpha;
  TaskBeta: ITaskBeta;
begin
  Document := TDocument.Create(...);
  // * Document irgendwie initialisiert *

  TaskAlpha := Document as ITaskAlpha;
  TaskBeta := Document as ITaskBeta;

  // Rest wie oben
Interfaces und Objekte auf diese Art zu mischen kann übrigens auch wegen der Referenzzählung bei Interfaces nach hinten losgehen, wenn man nicht aufpasst.

Geändert von Namenloser (26. Jul 2012 um 18:29 Uhr) Grund: Properties bei Interface vergessen
  Mit Zitat antworten Zitat