Ich sehe aktuell keinen Grund, das Ganze generisch zu machen. Es ist nur so, daß du das Pattern nicht korrekt umgesetzt hast und deswegen die Probleme mit dem Typ des result-Werts kommst.
So solltest die niemals
t.Accept(Visitor)
aufrufen, sondern immer
Visitor.Visit(t)
. Entsprechend muss das Accept gar nichts über den Result wissen, den es ja eh nur an den Visitor weiterreicht.
Eine brauchbare, allerdings so auf die Schnelle hingeschriebene, Implementierung angelehnt an Part 3 der oben genannten Artikelserie wäre sowas:
Delphi-Quellcode:
type
TVisitor = class(TInterfacedPersistent)
end;
TNode = class
strict private
FChildren: TObjectList<TNode>;
function GetChild(Index: Integer): TNode;
function GetChildCount: Integer;
public
constructor Create;
destructor Destroy; override;
procedure Accept(Visitor: TVisitor); virtual; abstract;
procedure AddChild(Node: TNode);
property ChildCount: Integer read GetChildCount;
property Children[Index: Integer]: TNode read GetChild;
end;
TNodeA = class(TNode)
strict private
FValue: Integer;
public
constructor Create(Value: Integer);
procedure Accept(Visitor: TVisitor); override;
property Value: Integer read FValue;
end;
TNodeB = class(TNode)
strict private
FValue: Double;
public
constructor Create(Value: Double);
procedure Accept(Visitor: TVisitor); override;
property Value: Double read FValue;
end;
INodeAVisitor = interface
['{290FB9EF-9F7E-4008-9ECA-C52169D200E0}']
procedure VisitNodeA(Instance: TNodeA);
end;
INodeBVisitor = interface
['{C893648E-FCA0-4FB2-9400-2AFE3B862256}']
procedure VisitNodeB(Instance: TNodeB);
end;
TNodeVisitor = class(TVisitor, INodeAVisitor, INodeBVisitor)
protected
procedure VisitNodeA(Node: TNodeA); virtual; abstract;
procedure VisitNodeB(Node: TNodeB); virtual; abstract;
public
procedure Visit(ANode: TNode); virtual;
end;
TConcatVisitor = class(TNodeVisitor)
private
FList: TStringList;
function GetResultValue: string;
protected
procedure VisitNodeA(Node: TNodeA); override;
procedure VisitNodeB(Node: TNodeB); override;
public
constructor Create;
destructor Destroy; override;
property ResultValue: string read GetResultValue;
end;
Delphi-Quellcode:
{ TNode }
procedure TNode.AddChild(Node: TNode);
begin
FChildren.Add(Node);
end;
constructor TNode.Create;
begin
inherited Create;
FChildren := TObjectList<TNode>.Create(True);
end;
destructor TNode.Destroy;
begin
FChildren.Free;
inherited;
end;
function TNode.GetChild(Index: Integer): TNode;
begin
Result := FChildren[Index];
end;
function TNode.GetChildCount: Integer;
begin
Result := FChildren.Count;
end;
{ TNodeA }
procedure TNodeA.Accept(Visitor: TVisitor);
var
vis: INodeAVisitor;
begin
if Supports(Visitor, INodeAVisitor, vis) then
vis.VisitNodeA(Self);
end;
constructor TNodeA.Create(Value: Integer);
begin
inherited Create;
FValue := Value;
end;
{ TNodeB }
procedure TNodeB.Accept(Visitor: TVisitor);
var
vis: INodeBVisitor;
begin
if Supports(Visitor, INodeBVisitor, vis) then
vis.VisitNodeB(Self);
end;
constructor TNodeB.Create(Value: Double);
begin
inherited Create;
FValue := Value;
end;
procedure TNodeVisitor.Visit(ANode: TNode);
begin
ANode.Accept(Self);
end;
constructor TConcatVisitor.Create;
begin
inherited Create;
FList := TStringList.Create();
end;
destructor TConcatVisitor.Destroy;
begin
FList.Free;
inherited Destroy;
end;
function TConcatVisitor.GetResultValue: string;
begin
Result := FList.Text;
end;
procedure TConcatVisitor.VisitNodeA(Node: TNodeA);
var
i: Integer;
res: string;
saveList: TStringList;
begin
saveList := FList;
try
FList := TStringList.Create;
try
FList.Add(IntToStr(Node.Value));
for i := 0 to Node.ChildCount - 1 do
begin
Visit(Node.Children[i]);
end;
res := string.Join(sLineBreak, FList.ToStringArray);
finally
FList.Free;
end;
finally
FList := saveList;
end;
FList.Add(res);
end;
procedure TConcatVisitor.VisitNodeB(Node: TNodeB);
var
i: Integer;
res: string;
saveList: TStringList;
begin
saveList := FList;
try
FList := TStringList.Create;
try
FList.Add(FloatToStr(Node.Value));
for i := 0 to Node.ChildCount - 1 do
begin
Visit(Node.Children[i]);
end;
res := string.Join(', ', FList.ToStringArray);
finally
FList.Free;
end;
finally
FList := saveList;
end;
FList.Add(res);
end;
Delphi-Quellcode:
procedure TForm495.FormCreate(Sender: TObject);
var
t: TNode;
s: string;
ConcatVisitor: TConcatVisitor;
begin
t := TNodeA.Create(10);
try
t.AddChild(TNodeB.Create(2.5));
ConcatVisitor := TConcatVisitor.Create;
try
ConcatVisitor.Visit(t);
s := ConcatVisitor.ResultValue;
finally
ConcatVisitor.Free;
end;
ShowMessage(s);
finally
t.Free;
end;
end;