Delphi-PRAXiS
Seite 3 von 4     123 4      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Neuen Beitrag zur Code-Library hinzufügen (https://www.delphipraxis.net/33-neuen-beitrag-zur-code-library-hinzufuegen/)
-   -   Pattern: Visitor (https://www.delphipraxis.net/163845-pattern-visitor.html)

Stevie 19. Okt 2011 13:04

AW: Pattern: Visitor
 
In diesem Zusammenhang find ich das Decorator Pattern sehr erwähnenswert. Dieses würde ich in bestimmten Fällen vorziehen. Einen Serializer z.B. würde ich (zumindest in neuen Delphi Versionen) niemals als Visitor sondern als Decorator implementieren.

implementation 19. Okt 2011 13:40

AW: Pattern: Visitor
 
Zitat:

Zitat von madas (Beitrag 1131227)
Das Ganze kannste auch noch ein wenig eleganter lösen, da in TuWasBesonderes immer
das Gleiche gemacht wird:

Delphi-Quellcode:
// Unit A
type
   IVisitor = interface
     procedure Visit(const x: TClass1); overload;
     procedure Visit(const x: TClass2); overload;
   end;
   TVisitableBase = class
     procedure AcceptVisitor(const v: IVisitor);
   end;
   TClass1 = class(TVisitableBase)
     // viele Methoden...
   end;
   TClass2 = class(TVisitableBase)
     // viele Methoden...
   end;

procedure TVisitableBase.AcceptVisitor(const v: IVisitor);
begin
   v.Visit(self);
end;

Nein, so geht's nicht. Hier würde ja jedes mal v.Visit(TVisitableBase) aufgerufen werden.
Das gibt's aber nicht. Es gibt lediglich Überladungen mit TClass1 und TClass2 und die muss ich auch entsprechend aufrufen ;)

madas 19. Okt 2011 14:02

AW: Pattern: Visitor
 
Zitat:

Zitat von implementation (Beitrag 1131266)
Nein, so geht's nicht. Hier würde ja jedes mal v.Visit(TVisitableBase) aufgerufen werden.
Das gibt's aber nicht. Es gibt lediglich Überladungen mit TClass1 und TClass2 und die muss ich auch entsprechend aufrufen ;)

Glaube ich nicht Tim, da Self in dem Moment eigentlich den Type der abgeleiteten Klasse haben müsste und nicht nur TVisitableBase.

Grüße.

madas 19. Okt 2011 14:09

AW: Pattern: Visitor
 
Zitat:

Zitat von Stevie (Beitrag 1131257)
In diesem Zusammenhang find ich das Decorator Pattern sehr erwähnenswert. Dieses würde ich in bestimmten Fällen vorziehen. Einen Serializer z.B. würde ich (zumindest in neuen Delphi Versionen) niemals als Visitor sondern als Decorator implementieren.

Danke für Deinen Hinweis. Werde ich mir bei Gelegenheit einmal anschauen.

Grüße.

SebE 19. Okt 2011 14:15

AW: Pattern: Visitor
 
Zitat:

Zitat von madas (Beitrag 1131269)
Zitat:

Zitat von implementation (Beitrag 1131266)
Nein, so geht's nicht. Hier würde ja jedes mal v.Visit(TVisitableBase) aufgerufen werden.
Das gibt's aber nicht. Es gibt lediglich Überladungen mit TClass1 und TClass2 und die muss ich auch entsprechend aufrufen ;)

Glaube ich nicht Tim, da Self in dem Moment eigentlich den Type der abgeleiteten Klasse haben müsste und nicht nur TVisitableBase.

Grüße.

Das weiß der Compiler doch nicht!
Overloading kommt doch über die Übersetzungszeit garnicht hinaus.

stahli 19. Okt 2011 14:22

AW: Pattern: Visitor
 
Ich erkenne auch kein Problem.
Die Klassen TClass1 und TClass2 müssen dem Compiler natürlich bekannt sein.
Und Self ist ja dann vom Typ TClass1 oder TClass2.
M.E. sollte eine solche Vererbung funktionieren.

madas 19. Okt 2011 14:42

AW: Pattern: Visitor
 
Zitat:

Zitat von stahli (Beitrag 1131275)
Ich erkenne auch kein Problem.
Die Klassen TClass1 und TClass2 müssen dem Compiler natürlich bekannt sein.
Und Self ist ja dann vom Typ TClass1 oder TClass2.
M.E. sollte eine solche Vererbung funktionieren.

implementation hat tatsächlich recht. Zu diesem Zeitpunkt hat Self den Type TVisitableBase. Hatte das anders in Erinnerung. Daher habe ich noch mal in einem alten Projekt nach gekramt und siehe da, dort hatte ich nur eine Methode Visit(element: TVisitableBase). In dieser wurde auf den Type von element getestet und dann mit dem gecasteten Element weiter verfahren.

Frage ist warum ein Test den richtigen Type ermitteln kann, aber Self nicht selbst von diesem Type ist???

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TVisitableBase = class;

  TVisitor = class(TPersistent)
  public
    constructor Create;

    procedure Visit(element: TVisitableBase); virtual;
  end;

  TVisitableBase = class(TPersistent)
  private
    FCaption: String;
  protected
  public
    constructor Create(caption: String);

    procedure AcceptVisitor(visitor: TVisitor); virtual;

    property Caption: String read FCaption write FCaption;
  end;

  TVisitableDerived = class(TVisitableBase)
  private
    FCount: Integer;
  public
    constructor Create(caption: String; Count: Integer);
    destructor Destroy; override;

    property Caption;
    property Count: Integer read FCount write FCount;
  end;

  TVisitorDerived = class(TVisitor)
  public
    constructor Create;

    procedure Visit(element: TVisitableDerived); overload;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TVisitableBase }

procedure TVisitableBase.AcceptVisitor(visitor: TVisitor);
begin
  if (Assigned(visitor)) then
    visitor.Visit(Self);
end;

constructor TVisitableBase.Create(caption: String);
begin
  inherited Create;
  FCaption := caption;
end;

{ TVisitor }

constructor TVisitor.Create;
begin
  inherited;
end;

procedure TVisitor.Visit(element: TVisitableBase);
begin
  if (element is TVisitableDerived) then
    ShowMessage('caption: ' + element.Caption + '; count: ' + IntToStr(TVisitableDerived(element).Count))
  else
    raise Exception.Create('Fehler: Base');
end;

{ TVisitableDerived }

constructor TVisitableDerived.Create(caption: String; Count: Integer);
begin
  inherited Create(caption);
  FCount := count;
end;

destructor TVisitableDerived.Destroy;
begin

  inherited;
end;

{ TVisitorDerived }

constructor TVisitorDerived.Create;
begin
  inherited Create;
end;

procedure TVisitorDerived.Visit(element: TVisitableDerived);
begin
  raise Exception.Create('Fehler: Derived');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  visitor: TVisitorDerived;
  element: TVisitableDerived;
begin
  visitor := TVisitorDerived.Create;
  element := TVisitableDerived.Create('Test', 100);
  try
    element.AcceptVisitor(visitor);
  finally
    element.Free;
    visitor.Free;
  end;
end;

end.

implementation 19. Okt 2011 15:05

AW: Pattern: Visitor
 
Darf ich mal kurz was in die Runde werfen?

Runtime <> Compiletime ;)

In TVisitableBase.Accept ist der formale Typ von Self: TVisitableBase, also wird die Überladung Visit(TVisitableBase) genommen.
In TVisitableDerived wird diese Methode jetzt nur vererbt, ohne dass sich der formale Typ von Self dort ändert, also ändert sich auch nicht, welche Überladung genommen wird.
Zur Laufzeit steckt in dieser Variable aber dann natürlich ein TVisitableDerived.

Wenn wir Accept in der abgeleiteten Klasse jetzt neu deklarieren, ist der formale Typ von Self dort nun TVisitableDerived, und es wird auch die richtige Überladung genutzt.

stahli 19. Okt 2011 15:14

AW: Pattern: Visitor
 
Oh ja. Ich hatte übersehen, dass overload schon zur Compilezeit ausgewertet wird. :oops:

Dann dürfte aber der Code
Delphi-Quellcode:
// Unit A
 type
    IVisitor = interface
      procedure Visit(const x: TClass1); overload;
      procedure Visit(const x: TClass2); overload;
    end;
    TVisitableBase = class
      procedure AcceptVisitor(const v: IVisitor);
    end;
    TClass1 = class(TVisitableBase)
      // viele Methoden...
    end;
    TClass2 = class(TVisitableBase)
      // viele Methoden...
    end;
 
procedure TVisitableBase.AcceptVisitor(const v: IVisitor);
 begin
    v.Visit(self);
 end;
nicht kompilieren, da es ja keine überladene procedure Visit für TVisitableBase gibt - oder?

Uwe Raabe 19. Okt 2011 15:17

AW: Pattern: Visitor
 
Feature Request: man bohre das Syntax-Higlighting soweit auf, daß es nicht-compilierenden Code mit der Fehlerstelle markiert...


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:01 Uhr.
Seite 3 von 4     123 4      

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