Inwiefern entkoppelt es mehr da man sich ja in beiden Fällen auf eine abstrakte Klasse/Interface bezieht?
Weil dann der Visitor entscheidet, wann und wie er das Accept aufruft. Er könnte das auch einem anderen Visitor überlassen, den er temporär erstellt und dann den Node an dessen Visit weitergibt. Das hatte ich mir auch schon überlegt, um die unterschiedlichen Separatoren (sLineBreak und ', ') zu abstrahieren.
Zitat:
Hierzu muss man das Einrückungslevel mitliefern, bzw. einen Präfixstring, der je nach Knoten anders ist, an die Kindknoten weiterreichen.
Das lässt sich aber ganz hervorragend innerhalb der Visitorklasse regeln. Der Knoten soll sich ja um sowas gar nicht kümmern. Der muss nur die nötigen Properties bereitstellen.
Hier (wieder) mal ein schnelles Beispiel basierend auf dem vorigen Code (Create, Destroy und GetResultValue entsprechen TContentVisitor). Es wird einfach die Baumstruktur mit entsprechenden Einrückungen und Präfix dargestellt. Dabei werden die Node-Typen unterschiedlich formatiert. Man sieht hier auch deutlich den Vorteil der virtuellen Visit Methode gegenüber einem Aufruf von Accept:
Delphi-Quellcode:
type
TIndentVisitor = class(TNodeVisitor)
private
FLevel: Integer;
FList: TStringList;
FPrefix: string;
function GetResultValue: string;
protected
procedure VisitNodeA(Node: TNodeA); override;
procedure VisitNodeB(Node: TNodeB); override;
public
constructor Create;
destructor Destroy; override;
procedure Visit(ANode: TNode); override;
property ResultValue: string read GetResultValue;
end;
Delphi-Quellcode:
procedure TIndentVisitor.Visit(ANode: TNode);
var
i: Integer;
savePrefix:
string;
begin
savePrefix := FPrefix;
inherited;
// hier wird implizit das Accept aufgerufen, was auf die jeweilige VisitNodeA/B Methode verzweigt
FList.Add(StringOfChar('
', 2*FLevel) + FPrefix);
Inc(FLevel);
for i := 0
to ANode.ChildCount - 1
do
begin
Visit(ANode.Children[i]);
end;
Dec(FLevel);
FPrefix := savePrefix;
end;
procedure TIndentVisitor.VisitNodeA(Node: TNodeA);
begin
FPrefix := FPrefix + '
.' + Node.ClassName;
end;
procedure TIndentVisitor.VisitNodeB(Node: TNodeB);
begin
FPrefix := FPrefix + '
.[' + Node.ClassName + '
]';
end;