目标是创建一个名为TURLString的类型,按如下方式调用:
var
newURl : TURLString;
begin
newURL.Append('http://').Append('www.thehost.com').Append('path/on/server').Append('?');
...lots of app logic...
newURL.AppendParam('name', 'value').Append('#').AppendParam('name', 'value');
...more params added...
result := httpClient.Get(newURL);
end;
使用这样定义的TURLString(注意它是一个记录):
//from actual code used
TURLString = record
private
FString : string;
public
function Append(APart : string) : TURLString;
function AppendParam(AParam, AValue : string) : TURLString;
end;
function TURLString.Append(APart: string) : TURLString;
begin
FString := FString + APart;
result := self;
end;
function TURLString.AppendParam(AParam, AValue: string): TURLString;
begin
if (not Empty) then
FString := FString + URL_AMB;
FString := FString + AParam + '=' + AValue;
result := self;
end;
当逐步执行流体调用时,值被附加,但退出时,它们恢复为传递给第一个追加调用的第一个字符串,newURL等于'http://'在调试追加调用时,您看到'http://www.thehost.com/path/on/server?name=value#name=value'。
这个概念可以用于记录吗?
为了消除记录复制的性能和内存使用问题,您可以使用指针作为方法的结果类型:
type
PURLString = ^TURLString;
TURLString = record
private
FString : string;
public
function Append(const APart : string) : PURLString;
function AppendParam(const AParam, AValue : string) : PURLString;
end;
function TURLString.Append(const APart: string) : PURLString;
begin
FString := FString + APart;
result := @self;
end;
function TURLString.AppendParam(const AParam, AValue: string): PURLString;
begin
if FString <> '' then
FString := FString + URL_AMB;
FString := FString + AParam + '=' + AValue;
result := @self;
end;
所以你可以调用你原来的TURLString,就像你希望的那样:
newURL.Append('http://').Append('www.thehost.com').Append(...
对于方法的字符串参数,不要忘记const
关键字。
newURL.Append('http://')^.Append('www.thehost.com')^.Append(...
,但实际上Delphi编译器足够聪明,可以隐式地添加^符号。
使用这个技巧,您不必创建或释放您的newURL
实例。注意,只有引用计数的形参(字符串、变量、接口)才会在堆栈上初始化:整型或双精度型将是纯随机的。
这正是我在SynProject文档工具中用于创建一些RTF内容的方法(至少在第一个版本中,现在我使用类而不是记录,因为我想添加继承)。
记录样式为每个呼叫创建一个新的,匿名的(因此无法访问)记录,Result = self;
行将"当前"记录复制到新记录。这可能不是你想要的。正如David所说,您必须将(匿名)最终结果分配给您声明的记录变量,这样您才能最终访问最终结果。
如果您使用引用类型(对象或接口),它将返回对自身的引用,并且不会生成新对象(也不会复制任何对象)。
如果你使用的是像记录这样的值类型,那么你需要将最终返回的结果赋值给一个变量:
newURL := newURL.Append('http://').Append('www.thehost.com');
如果使用类实例之类的引用类型,则可以使用问题中使用的语法。
引用类型方法将数据类型视为可变的,而对于值类型,您最好实现不可变的数据类型。
看一下这里的TPathBuilder实现。它的主要目的是构建文件路径,但你可以理解。源代码包含在文章中。