如何在Delphi中用Records实现无拷贝的Builder设计模式?
Delphi中用Record实现无拷贝链式Builder模式的可行方案
针对你想用Delphi Record实现无拷贝链式Builder的需求,以下是几个实用的解决方案,兼顾效率和语法简洁性:
方案1:指针+自动解引用调用(无拷贝,语法接近链式)
通过返回Record指针,并利用Delphi支持指针直接调用方法的特性,避免拷贝且无需手动解引用:
type TAlert = record Title: string; Message: string; end; PAlertBuilder = ^TAlertBuilder; TAlertBuilder = record private FTitle: string; FMessage: string; function GetSelf: PAlertBuilder; inline; public // 初始化堆上的Builder实例 class function Init: PAlertBuilder; static; inline; // 释放堆内存 procedure Free; inline; // 链式方法,返回自身指针 function SetTitle(const ATitle: string): PAlertBuilder; inline; function SetMessage(const AMessage: string): PAlertBuilder; inline; // 构建最终对象 function Build: TAlert; inline; end; implementation class function TAlertBuilder.Init: PAlertBuilder; begin New(Result); end; procedure TAlertBuilder.Free; begin Dispose(@Self); end; function TAlertBuilder.GetSelf: PAlertBuilder; begin Result := @Self; end; function TAlertBuilder.SetTitle(const ATitle: string): PAlertBuilder; begin FTitle := ATitle; Result := GetSelf; end; function TAlertBuilder.SetMessage(const AMessage: string): PAlertBuilder; begin FMessage := AMessage; Result := GetSelf; end; function TAlertBuilder.Build: TAlert; begin Result.Title := FTitle; Result.Message := FMessage; end;
调用示例:
var Alert: TAlert; Builder: PAlertBuilder; begin Builder := TAlertBuilder.Init; try // 直接通过指针链式调用,无需解引用 Alert := Builder.SetTitle('系统提示').SetMessage('操作执行成功').Build; finally Builder.Free; end; end;
这个方案完全无拷贝,所有操作都在堆上的Record实例上进行,inline方法可以抵消指针操作的微小开销,仅需手动管理内存(用try-finally包裹即可)。
方案2:栈上Record+With语句(零开销,语法简洁)
放弃传统链式返回的思路,直接用栈上Record结合with语句,完全无拷贝且无需内存管理:
type TAlert = record Title: string; Message: string; end; TAlertBuilder = record private FTitle: string; FMessage: string; public procedure SetTitle(const ATitle: string); inline; procedure SetMessage(const AMessage: string); inline; function Build: TAlert; inline; end; implementation procedure TAlertBuilder.SetTitle(const ATitle: string); begin FTitle := ATitle; end; procedure TAlertBuilder.SetMessage(const AMessage: string); begin FMessage := AMessage; end; function TAlertBuilder.Build: TAlert; begin Result.Title := FTitle; Result.Message := FMessage; end;
调用示例:
var Alert: TAlert; begin with TAlertBuilder.Create do begin SetTitle('系统提示'); SetMessage('操作执行成功'); Alert := Build; end; end;
这个方案直接操作栈上的Record实例,没有任何拷贝或内存分配,效率最高,语法也足够简洁,适合对性能要求极高的场景。
方案3:Delphi 11+托管Record(语法完全匹配链式,低开销)
如果你的项目使用Delphi 11或更高版本,可以利用托管Record特性,自动管理堆内存,实现和Kotlin/Swift完全一致的链式语法:
type TAlert = record Title: string; Message: string; end; TAlertBuilder = record private // 用指针存储实际数据,避免拷贝 FData: ^record Title: string; Message: string; end; procedure InitData; procedure FreeData; public function SetTitle(const ATitle: string): TAlertBuilder; inline; function SetMessage(const AMessage: string): TAlertBuilder; inline; function Build: TAlert; inline; // 托管Record的生命周期管理 class operator Initialize(var Value: TAlertBuilder); class operator Finalize(var Value: TAlertBuilder); end; implementation class operator TAlertBuilder.Initialize(var Value: TAlertBuilder); begin Value.InitData; end; class operator TAlertBuilder.Finalize(var Value: TAlertBuilder); begin Value.FreeData; end; procedure TAlertBuilder.InitData; begin New(FData); end; procedure TAlertBuilder.FreeData; begin Dispose(FData); end; function TAlertBuilder.SetTitle(const ATitle: string): TAlertBuilder; begin FData.Title := ATitle; Result := Self; end; function TAlertBuilder.SetMessage(const AMessage: string): TAlertBuilder; begin FData.Message := AMessage; Result := Self; end; function TAlertBuilder.Build: TAlert; begin Result.Title := FData.Title; Result.Message := FData.Message; end;
调用示例:
var Alert: TAlert; begin // 和Kotlin完全一致的链式语法 Alert := TAlertBuilder.Create.SetTitle('系统提示').SetMessage('操作执行成功').Build; end;
这个方案中,Record内部仅存储一个指针,拷贝指针的开销可以忽略不计,且托管特性会自动处理内存释放,无需手动管理,是最接近你目标的方案。
关于absolute关键字的说明
你尝试的absolute关键字主要用于让变量共享内存地址,但Delphi不允许在Record字段定义中直接引用Self(Self是方法内部的隐含参数),因此无法通过absolute实现无拷贝链式调用,上述方案更具实用性。
内容的提问来源于stack exchange,提问作者zeus
相关产品推荐
相关产品推荐

