Einzelnen Beitrag anzeigen

Ghostwalker

Registriert seit: 16. Jun 2003
Ort: Schönwald
1.299 Beiträge
 
Delphi 10.3 Rio
 
#1

Interfaces, Factory- und Singletonpattern

  Alt 5. Mai 2018, 06:31
Guten Morgen

Ich versuch mir grad eine Factory zu bauen, die mir verschiedene Dialoge handeln soll. Dazu hab ich mir zuerstmal ein einfaches Interfaces gebaut:

Delphi-Quellcode:
Type
  IVTDialogCall = Interface
    ['{6EB35D36-EE58-43A3-814E-1173DCA9CBCF}']
    function Call(var value:TValue):boolean;
  End;
Dafür dann eine Basis-Klasse die wie folgt aussieht:

Delphi-Quellcode:
  TVTDialogBase = Class(TInterfacedPersistent,IVTDialogCall)
    private
    protected
      //Must be overridend by a descend class
      Procedure BeforeCall(sender:TVTDialogBase;var value:TValue);virtual;
      Procedure AfterCall(sender:TVTDialogBase;var value:TValue;callresult:boolean);virtual;
      function Execute(var value:TValue):boolean;virtual;abstract;
    public
      function Call(var value:TValue):boolean;
    published
  End;
Jeder spezifische Dialog leitet sich von dieser Basisklasse ab:
Delphi-Quellcode:
  TVTColorDialog = Class(TVTDialogBase)
    private
      fdlg : TColorDialog;
    protected
      Procedure BeforeCall(sender:TVTDialogBase;var value:TValue);override;
      procedure AfterCall(sender:TVTDialogBase;var value:TValue;CallResult:boolean);override;
      function Execute(var value:TValue):boolean;override;
    public
    published
  End;
Jede Klasse registriert sich im Initialization abschnitt bei der Factory-Klasse. Soweit tut das ganze.
Delphi-Quellcode:
Class function DialogManager.CallDialog(AName: string; var value: TValue):boolean;
var
  intf : IVTDialogCall;
  dm : TDialogItem;
begin
  result := false;
  if not (fdialogs.ContainsKey(AName)) then exit;
  dm := fdialogs[AName];
  if (dm.Ainst = NIL) then
  begin
    dm.AInst := CreateInstance(dm.AClass);
    fdialogs.AddOrSetValue(Aname,dm);
  end;
  if (dm.AInst <> NIL) then
  begin
    dm.AInst := CreateInstance(dm.AClass);
    fdialogs.AddOrSetValue(Aname,dm);
  end;
  Supports(dm.Ainst,IVTDialogCall,intf);
  if (intf <> NIL) then
    result := intf.Call(value);
end;
Diese Methode der Factory implentiert jetzt den Aufruf des Dialoges. Dabei ruft CreateInstance via RTTI den Constructor der Dialog-Klasse auf. Diese wird gespeichert, um zu vermeiden das die Klasse jedesmal neu erzeugt
werden muss. Nu kracht es allerdings beim Supports mit einer Zugriffsverletzung, was ich so nicht ganz
nachvollziehen kann. Den dm.AInst ist definitiv eine Instanz der Klasse TVTColorDialog (sagt mir der Debugger).

Zusatzinfo:

Das Problem tritt auf, seit ich TVTBaseDialog nicht mehr von TInterfacedObject sonder jetzt von TInterfacedPersistent ableite. Der Grund dafür ist schlicht das ich die Instanzen selbst verwalte und mir die automatische Verwaltung (Referenzzählung usw.) nicht brauche.

Hier noch die Methode CreateInstanz:
Delphi-Quellcode:
var
  ctx : TRttiContext;
  rt : TRttiType;
  rm : TRttiMethod;

begin
  ctx := TRttiContext.create;
  rt := ctx.GetType(AClass.ClassInfo);
  for rm in rt.GetDeclaredMethods do
  begin
    if (rm.IsConstructor) then
    begin
      result := rm.Invoke(AClass,[]).AsObject as TInterfacedPersistent;
      break;
    end;
  end;
  ctx.Free;
end;
Kann mir jemand sagen wo das Problem liegt ?
Uwe
e=mc² or energy = milk * coffee²
  Mit Zitat antworten Zitat