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, 07:27
okok... das Beispiel war wohl zu minimiert.
Delphi-Quellcode:
unit Base;
interface
type
    Visitor = class;
    Base = class
    public
      procedure Accept(v : Visitor);virtual;abstract;
    end;

    A = class(Base)
    public
      procedure Accept(v : Visitor);override;
      function AZeugs() : String;
    end;

    B = class(Base)
    public
      procedure Accept(v : Visitor);override;
      function BZeugs() : String;
    end;

    Visitor = class
    public
        procedure Visit(a : A); overload;
        procedure Visit(b : B); overload;
    end;

implementation

{ Visitor }
procedure Visitor.Visit(a: A);
begin
    WriteLn(a.AZeugs());
end;

procedure Visitor.Visit(b: B);
begin
    WriteLn(b.BZeugs());
end;

//...

end.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Visitor Pattern

  Alt 15. Jul 2010, 07:53
Also doch das Gleiche.

Wenn es aufgeteilt werden soll, dann mußt man es auf eine gemeinsame Basis (Base) bringen.
Delphi-Quellcode:
unit BaseUnit;

interface

  type
    Visitor = class;
    Base = class
    public
      procedure Accept(v : Visitor); virtual; abstract;
      function Zeugs() : String; virtual; abstract;
    end;

    Visitor = class
    public
      procedure Visit(b : Base);
    end;

implementation

  { Visitor }
  procedure Visitor.Visit(b: Base);
  begin
    WriteLn(b.Zeugs());
  end;

  //...

end.
Delphi-Quellcode:
unit AUnit;

interface
  uses
    BaseUnit;

  type
    A = class(Base)
    public
      procedure Accept(v : Visitor); override;
      function Zeugs() : String; override;
    end;

implementation
  ...
Delphi-Quellcode:
unit BUnit;

interface
  uses
    BaseUnit;

  type
    B = class(Base)
    public
      procedure Accept(v : Visitor); override;
      function Zeugs() : String; override;
    end;

implementation
  ...
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
hansmaad

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

AW: Visitor Pattern

  Alt 15. Jul 2010, 08:04
grrr...
Delphi-Quellcode:
Schiff = class(Fahrzeug)
public
  // ...
  property Kabinen : Integer read Kabinenanzahl;
end
Delphi-Quellcode:
Auto = class(Fahrzeug)
public
  // ...
  property Reifen: Integer read Reifenanzahl;
end
Delphi-Quellcode:
procedure ReportVisitor.Visit(s : Schiff);
begin
  WriteLn('Das Schiff hat ' + s.Kabinen + ' Kabinen');
  // 100 weitere Schiffsdaten
end;
procedure ReportVisitor.Visit(a : Auto);
begin
  WriteLn('Das Auto hat ' + s.Reifen+ ' Räder');
  // 100 weitere Autodaten
end;

Nun glaubt mir mal, dass das hier ein potentieller Anwendungsfall des Visitor Musters ist.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Visitor Pattern

  Alt 15. Jul 2010, 08:26
Wenn es aufgeteilt werden soll und sich dann nicht alle Klassen gegenseitig kennen können, dann muß man sich einfach auf eine gemeinsame Basis beschränken, welche sich kennt und wovon dann alles Andere/Unbekannte abgeleitet wird.

Ich denka mal das letze Beispiel dürfte eher dem Pattern entsprechen.
Da gibt es dann passende Visitor, die wissen was zu machen ist
und welche über einer gemeinsame Basis aufrufbar sind.

Delphi-Quellcode:
unit BaseUnit;

interface
  type
    Visitor = class;
    Base = class
    public
      procedure Accept(v : Visitor); virtual; abstract;
      function Visit(v : Visitor) : Integer; virtual; abstract;
    end;

    Visitor = class
    public
      procedure Visit(b : Base);
    end;

implementation

  { Visitor }
  procedure Visitor.Visit(b : Base);
  begin
    WriteLn(b.Visit(self));
  end;

  //...

end.

////////////////////////////////////

Schiff = class(Base)
public
  procedure Accept(v : Visitor); override;
  function Visit(v : Visitor) : Integer; override;
  // ...
  property Kabinen : Integer read Kabinenanzahl;
end;

function Schiff.Visit(v : Visitor) : Integer;
begin
  if v is Base then
    Result := Kabinen
  else
    ...
end;

Wobei man auch auf Seiten des Visitors aufsplitten könnte, aber das wäre dann weniger flexibel.
Delphi-Quellcode:
unit BaseUnit;

interface

  type
    Visitor = class;
    Base = class
    public
      procedure Accept(v : Visitor); virtual; abstract;
    end;

    StrBase = class(Base)
    public
      function StrVisit() : String; virtual; abstract;
    end;

    IntBase = class(Base)
    public
      function IntVisit() : Integer; virtual; abstract;
    end;

    Visitor = class
    public
      procedure Visit(b : Base);
    end;

implementation

  { Visitor }
  procedure Visitor.Visit(b: Base);
  begin
    if b is StrBase then
      WriteLn(b.StrVisit);
    else if b is IntBase then
      WriteLn(b.IntVisit);
  end;

  //...

end.
oder
Delphi-Quellcode:
unit BaseUnit;

interface

  type
    TVisitType = (vtInt, vtStr);
    Visitor = class;
    Base = class
    public
      procedure Accept(v : Visitor); virtual; abstract;
      funktion GetVisitType: TVisitType; virtual; abstract;
      function IntVisit() : Integer; virtual; {abstract;}
      function StrVisit() : String; virtual; {abstract;}
      // {...} vielleicht einen leeren Dummy verwenden,
      // damit man nicht überall alles überschreiben muß
    end;

    Visitor = class
    public
      procedure Visit(b : Base);
    end;

implementation

  { Visitor }
  procedure Visitor.Visit(b: Base);
  begin
    case b.GetVisitType of
      vtInt: WriteLn(b.IntVisit);
      vtStr: WriteLn(b.StrVisit);
      else ...
    end;
  end;

  //...

end.

Eventuell kannst du auch den Visitor aufteilen.
Da kennt dann jeder Visitornachfahre seine Base-Class und weiß was mit ihr zu machen ist.
Delphi-Quellcode:
unit BaseUnit;

interface
  type
    Visitor = class;
    Base = class
    public
      procedure Accept(v : Visitor); virtual; abstract;
      procedure Visit(v : Visitor); virtual; abstract;
    end;

    Visitor = class
    public
      procedure Visit(b : Base);
    end;

implementation

  { Visitor }
  procedure Visitor.Visit(b : Base);
  begin
    b.Visit(self);
  end;

  //...

end.

///////////////////////////////////////////////////////

unit StrBaseUnit;

interface
  uses
    BaseUnit;

  type
    StrBase = class()Base
    public
      procedure Accept(v : Visitor); override;
      procedure StrVisit; virtual; abstract;
    end;

    StrVisitor = class(Visitor)
    public
      procedure StrVisit(b : Base);
    end;

implementation

  { Visitor }
  procedure StrVisitor.StrVisit(b : Base);
  begin
    WriteLn((b as StrBase).StrVisit);
  end;

  //...

end.
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu (15. Jul 2010 um 08:35 Uhr)
  Mit Zitat antworten Zitat
hansmaad

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

AW: Visitor Pattern

  Alt 15. Jul 2010, 08:53
Also danke für deine Mühen, aber 1. versteh ich nicht alles und 2. hat das denke ich nicht mehr viel mit Visitor zu tun.
Code:
procedure Visit(b : Base);
und eine Typunterscheidung in if else, switch case oder Zugriff über die gemeinsame Schnittstelle ist keine Alternative. Dafür brauche ich keinen Visitor.
Da kann ich auch direkt
Delphi-Quellcode:
for base in Liste do
begin
  if base is Dies : Tu dies
  if base is Das : Tu das
  ...
end;
oder
Delphi-Quellcode:
for base in Liste do
begin
  TuWasFuerAlleBaseGilt(base);
end;
Wenn es mit dem Visitor nicht geht, werde ich eher einen Weg wie in #4 gehen. Ob der Visitor überhaupt das richtige Muster ist müsste ich eh noch entscheiden. Ich wollte nur vorher mal sehen, ob es sich überhautpt lohnt darüber nachzudenken, oder ob es in Delphi einfach quasi unmöglich ist.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Visitor Pattern

  Alt 15. Jul 2010, 09:10
und eine Typunterscheidung in if else, switch case oder Zugriff über die gemeinsame Schnittstelle ist keine Alternative. Dafür brauche ich keinen Visitor.
Da kann ich auch direkt ...
Das kommt drauf an ... irgendo muß ja unterschieden werden, wenn es mehrere Möglichkeiten gibt, da man sich nicht auf eine Basis einigen konnte.

Aber der Vorteil mit dem "Visitor" wäre dann, daß diese Unterscheidung dort implementiert ist und man sich extern nicht darum kümmern muß
Ich denke mal, das soll wohl der Grund für dieses Pattern sein?

Stell dir mal vpr du rufst dieses an meheren Stellen auf, dann müßtest du, bei Einfügen einer neuen Klasse (Base-Nachfahre) an allen Stellen dieses anpassen,
anstatt z.B. nur einen passenden Visitor-Nachfahren zu erstellen (falls ein Anderer Visitor es nicht schon kann).
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
hansmaad

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

AW: Visitor Pattern

  Alt 15. Jul 2010, 09:33
...irgendo muß ja unterschieden werden,...
->Polymorphie

Stell dir mal vpr du rufst dieses an meheren Stellen auf, dann müßtest du, bei Einfügen einer neuen Klasse (Base-Nachfahre) an allen Stellen dieses anpassen,
anstatt z.B. nur einen passenden Visitor-Nachfahren zu erstellen (falls ein Anderer Visitor es nicht schon kann).
Richtig, das hatte ich ja schon auf der ersten Seite erwähnt. Wenn es häufig neue Elementklassen gibt (Base-Nachfahren) ist Visitor schlecht. Auf dieser Seite ist das System nciht "offen für Erweiterungen".
Wenn allerdings meine Elementklassenhierachie ein fertiges System ist, dass nicht mehr um neue Elemente erweitert wird, aber die Funktionalität dieser Elemente häufig erweitert wird, ist eine Lösung mit Visitor sehr wohl "offen für Erweiterungen". In diesem Fall bleibt nämlich die gesamte Hierachie wie sie ist und man leitet nur einen neuen Visitor von der Visitor Basisklasse ab.
  Mit Zitat antworten Zitat
Blup

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

AW: Visitor Pattern

  Alt 15. Jul 2010, 09:00
Keine Ahnung ob dir das hilft:
Delphi-Quellcode:
unit Base;

type
  TVisistor = class;

  TBase = class
  public
    procedure Accept(v : TVisitor); virtual; abstract;
  end;

  TVisitor = class
  public
    procedure Visit(ABase: TBase); virtual; abstract;
  end;
Delphi-Quellcode:
unit ClassA;

uses
  Base;

type
  TA = class(TBase)
  public
    procedure Accept(v : TVisitor); override;
  end;
Delphi-Quellcode:
unit ClassB;

uses
  Base;

type
  TB = class(TBase)
  public
    procedure Accept(v : TVisitor); override;
  end;
Delphi-Quellcode:
unit VisitorAB;

uses
  Base, ClassA, ClassB;

type
  TVisitorAB
  private
    procedure VisitA(A: TA);
    procedure VisitB(B: TB);
  public
    procedure Visit(ABase: TBase); override;
  end;

implementation
  
procedure TVisitorAB.Visit(ABase: TBase);
begin
  if ABase is TA then
    VisitA(TA(ABase));
  if ABase is TB then
    VisitB(TB(ABase));
end;
Statt die Funktionen für die konkreten Klassen im Visitor zu implementieren, könnte man diese auch in spezille Klassen auslagern, die beim Visitor mit der jeweils unterstützten Baseklasse registriert werden.
  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 08:48 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