AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Visitor Pattern

Ein Thema von hansmaad · begonnen am 15. Jul 2010 · letzter Beitrag vom 18. Aug 2010
Antwort Antwort
hansmaad

Registriert seit: 25. Feb 2010
52 Beiträge
 
Delphi 2010 Professional
 
#1

AW: Visitor Pattern

  Alt 15. Jul 2010, 10:39
Ok, das sieht ja ganz nett aus (mal davon abgesehen, dass Interfaces für meinen Geschmack generell furchtbar aussehen).

das IBaseVisitor Interface kann ich mir bei einer abstrakten Basisklasse schenken, da es keine Base Instanzen gibt, korrekt?

TVisitor.VisitA(Instance: TA);
TVisitor.VisitB(Instance: TB);

würde ich wohl abstrakt machen und konkrete Besucher von TVisitor ableiten. Das wäre dann im Stil 'Template Methode'. Dieser Supports / Not Supported Kram wird von der Basisklasse behandelt, der konkrete Besucher kümmert sich nur noch um A und B.

Auf den ersten Blick scheint mir das eine ganz brauchbare Lösung zu sein
Ich werde das mal ausprobieren,
Danke!
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.487 Beiträge
 
Delphi 12 Athens
 
#2

AW: Visitor Pattern

  Alt 15. Jul 2010, 10:59
Im Normalfall Interface-Parameter besser als const deklarieren.
Sonst erfolgt unnötige Referenzzählung (wie auch bei string).
Delphi-Quellcode:
type
  IVisitor = interface
    ['{59A6BE7C-6BD7-4746-AA37-F42DCB6D8D01}']
    procedure Visit(const Instance: IInterface);
    procedure NotSupported(const Name: string);
  end;

  IVisited = interface
    ['{6C55ECC2-E1AB-43DD-96EC-755FF5C12400}']
    procedure Accept(const Visitor: IVisitor);
  end;
  Mit Zitat antworten Zitat
hansmaad

Registriert seit: 25. Feb 2010
52 Beiträge
 
Delphi 2010 Professional
 
#3

AW: Visitor Pattern

  Alt 15. Jul 2010, 11:59
Im Normalfall Interface-Parameter besser als const deklarieren.
Sonst erfolgt unnötige Referenzzählung (wie auch bei string).
Was bedeuten in Delphi konstante Parameter? Was kann ich auf ihnen ausrufen? Von C++ kenne ich konstante Methoden, die auf konstanten Instanzen aufgerufen werden können. Sowas gibt es hier aber denke ich nicht.
Was bedeutet es einen const Visitor zu übergeben. Gilt dieses const nur für die Schnittstelle (eigentlich sinnlos da Schnittstellen gar keine Daten haben)? Oder weiß der Compiler, dass die Implementierung von Visit die Visitorinstanz nicht verändert? Was passiert, wenn Visit die Istanz verändert?
  Mit Zitat antworten Zitat
Namenloser

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

AW: Visitor Pattern

  Alt 15. Jul 2010, 17:16
Oder weiß der Compiler, dass die Implementierung von Visit die Visitorinstanz nicht verändert? Was passiert, wenn Visit die Istanz verändert?
Genau das ist const : Eine Schreibschutz-Markierung. Das erlaubt natürlich gewisse Compileroptimierungen, genauer gesagt kann einfach ein Pointer auf das Original übergeben werden, statt dass eine Kopie auf dem Stack angelegt werden muss.

Zu deiner 2. Frage: Das geht nicht, der Compiler schmeißt dann einen Fehler.

Im Grunde ist const das gleiche wie var , nur mit dem Unterschied, dass das Original garantiert nicht verändert wird.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.360 Beiträge
 
Delphi 12 Athens
 
#5

AW: Visitor Pattern

  Alt 15. Jul 2010, 17:34
CONST ist nicht immer genau das Gleiche wie VAR,
das siehst du, wenn du z.B. const i: Integer mit i: integer und var i: Integer vergleichst, denn dieses wird delphi meißt so weit optimieren, daß hier kein Pointer, sondern direkt der Wert mitgenommen wird, trots des CONST.
dennoch können, vorallem bei referenzzählenden Typen oder gar dem "kranken" WideString und Records, durch das CONST dennoch so einige kleine Stellen optimiert werden, da man hier explizit angibt, daß der Wert nicht verändert wird.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
hansmaad

Registriert seit: 25. Feb 2010
52 Beiträge
 
Delphi 2010 Professional
 
#6

AW: Visitor Pattern

  Alt 16. Jul 2010, 10:11
Also jetzt brauch ich doch noch mal eine genauere Erklärung.
Ich habe es gerade getestet und ich kann auf einem const Argument alles aufrufen und es auch durch nicht konstante Methoden verändern. Was heißt hier const?

Delphi-Quellcode:
type
    Test = class
    private
        x : Integer;
    public
        constructor Create;
        procedure Konstant();
        procedure NichtKonstant();
    end;

{ Test }

constructor Test.Create;
begin
    x := 1;
end;

procedure Test.Konstant;
begin
    WriteLn(IntToStr(x));
end;

procedure Test.NichtKonstant;
begin
    x := x * 2;
end;

procedure Foo(const t : Test);
begin
    t.Konstant;
    t.NichtKonstant;
    t.Konstant;
end;


var
    Tester : Test;
begin
    Tester := Test.Create;

    Foo(Tester);

    Tester.Free;
    ReadLn;
end.
Code:
1
2
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.360 Beiträge
 
Delphi 12 Athens
 
#7

AW: Visitor Pattern

  Alt 16. Jul 2010, 10:21
CONST bezieht sich immer nur auf die Variable/Parameter.

Es kann also der Parameterwert nicht verändert werden (Interface freigeben oder ein Anderes einfügen), aber den Inhalt von Objekten und Interfaces betrifft dieses nicht.

t.NichtKonstant; ändert ja nur den Inhalt und nicht den Parameter, bzw. den Zeiger in dem Parameter, welcher auf das Objekt zeigt.

sowas geht nicht
Delphi-Quellcode:
procedure Foo(const t : Test);
begin
  t := nil;
  t := WasAnderes;
end;
Es gibt nur eine Stelle, wo CONST wirklich versagt ... und das ist bei Records, welche "neuerdings" mit Record-Methoden versehen werden können.
Eigentlich dürfte man bei Records, da sie nicht über einen Zeiger, sondern direkt verwalte werden, nicht den Inhalt verändern, welches aber dennoch leider über die RecordMethoden möglich ist.
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu (16. Jul 2010 um 10:25 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.639 Beiträge
 
Delphi 12 Athens
 
#8

AW: Visitor Pattern

  Alt 15. Jul 2010, 16:44
Im Normalfall Interface-Parameter besser als const deklarieren.
Sonst erfolgt unnötige Referenzzählung (wie auch bei string).
Delphi-Quellcode:
type
  IVisitor = interface
    ['{59A6BE7C-6BD7-4746-AA37-F42DCB6D8D01}']
    procedure Visit(const Instance: IInterface);
    procedure NotSupported(const Name: string);
  end;

  IVisited = interface
    ['{6C55ECC2-E1AB-43DD-96EC-755FF5C12400}']
    procedure Accept(const Visitor: IVisitor);
  end;
Ist nur meine persönliche Meinung, aber ich würde genau das nicht machen. Die "überflüssige" Referenzzählung ist ein Inkrement und ein Dekrement eines internen Zählers und fällt überhaupt nicht ins Gewicht. Die Deklaration als const allerding übergibt einen Pointer auf ein Interface und bei jedem Zugriff auf das Interface erfolgt eine zusätzliche Dereferenzierung des Pointers (und übrigens auch noch eine Referenzzählung). Also lediglich in dem Fall, wo das Interface innerhalb der Methode so gut wie nicht verwendet wird, mag die const Variante marginal schneller sein - in allen anderen Fällen ist sie weniger performant.
Uwe Raabe
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.639 Beiträge
 
Delphi 12 Athens
 
#9

AW: Visitor Pattern

  Alt 15. Jul 2010, 11:16
das IBaseVisitor Interface kann ich mir bei einer abstrakten Basisklasse schenken, da es keine Base Instanzen gibt, korrekt
Das hängt davon ab, was dein Visitor tun soll. So könnte ein Visitor, der lediglich auf TBase-Eigenschaften und Methoden zugreift, auch nur das IBaseVisitor-Interface implementieren und die IAVisitor- und IBVisitor-Interfaces gar nicht implementieren. Ergänzend dazu muss man dann allerdings die Implementationen von Accept in TA und TB leicht abwandeln.

Delphi-Quellcode:
procedure TA.Accept(Visitor: IVisitor);
var
  MyVisitor: IAVisitor;
begin
  if Supports(Visitor, IAVisitor, MyVisitor) then
    MyVisitor.VisitA(Self)
  else
    inherited;
end;
Delphi-Quellcode:
procedure TB.Accept(Visitor: IVisitor);
var
  MyVisitor: IBVisitor;
begin
  if Supports(Visitor, IBVisitor, MyVisitor) then
    MyVisitor.VisitB(Self)
  else
    inherited;
end;
Wenn nun der Visitor das passende Interface nicht implementiert, wird einfach die Accept-Methode des Vorfahren aufgerufen.

Delphi-Quellcode:
unit uBaseVisitor;

interface

uses
  Classes, uVisitorTypes, uBase;

type
  TBaseVisitor = class(TInterfacedObject, IVisitor, IBaseVisitor)
  protected
    procedure NotSupported(const Name: string);
    procedure VisitBase(Instance: TBase);
  public
    procedure Visit(Instance: IInterface);
  end;

implementation

uses
  SysUtils;

procedure TBaseVisitor.NotSupported(const Name: string);
begin
  // nach Bedarf ignorieren oder Fehler melden
end;

procedure TBaseVisitor.Visit(Instance: IInterface);
var
  visited: IVisited;
begin
  if Supports(Instance, IVisited, visited) then
    visited.Accept(Self)
  else
    // nach Bedarf ignorieren oder Fehler melden
end;

procedure TBaseVisitor.VisitBase(Instance: TBase);
begin
  // tue was mit Instance, was jedes TBase kann
end;

end.


TVisitor.VisitA(Instance: TA);
TVisitor.VisitB(Instance: TB);

würde ich wohl abstrakt machen und konkrete Besucher von TVisitor ableiten. Das wäre dann im Stil 'Template Methode'. Dieser Supports / Not Supported Kram wird von der Basisklasse behandelt, der konkrete Besucher kümmert sich nur noch um A und B.
Das hängt natürlich auch von deinem konkreten Fall ab. In meinen Anwendungen habe ich sowohl Visitors, die von einem Basis-Visitor abgeleitet sind, als auch solche, die von Grund auf neu implementiert werden.

Wenn irgendeine Struktur (Liste, Baum, ...) von TBase-Abkömmligen vorliegt, könnte man einen Visitor schreiben, der die Struktur iteriert und alle Instanzen zählt. Der bräcuhte dann nur IBaseVisitor implementieren.

Es gibt da keine allgemeingültige Vorgehensweise - wie so oft in unserer Branche...

Ich hatte mal vor, über das Thema "Visitor - eine praktikable Implementierung" einen Artikel zu schreiben, in dem die obige Implentierung erläutert und verschiedene Szenarien durchgespielt werden, aber es kommt halt immer etwas dazwischen.

Wär' ja vielleicht auch was für die Delphi-Tage???
Uwe Raabe
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:55 Uhr.
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