You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 10:43:14