【delphi】类和记录的 helpers(助手)


前言

        Delphi 从XE版本开始提供类和记录的 Helper(助手) 封装,这样就可以很方便的在不修改原来类或者记录的原始定义情况下,给类和记录增加新的功能。 本文简要介绍 Helper 的实现,最后实际举例实现了TJSONObject的Helper,让使用delphi原生的JSON对象也能像SuperObject一样书写方式操作。

一、关于类和记录的 helpers(助手)

        Helpers(助手)是一种不使用继承的方法来扩充类或者记录的功能,对于记录类型更是有用,因为类可以通过继承来增加功能二记录不可以继承。适用于一些没有源代码或者源代码不适合进行变更的类的扩展。对于自己原始设计的程序,不应该使用这种类的扩展方法,应该始终依赖于普通的类继承和接口实现。

二、helpers(助手)语法定义

type
   identifierName = class|record helper [(ancestor list)] for TypeIdentifierName
     memberList
   end;

ancestor list 是可选的,而且只能适用于类Helpers;助手类型不能声明实例数据,但允许使用类字段(class fields);其他可见性范围规则和成员列表语法与普通类和记录类型相同。

例如:

type
  TJSONObjectHelper = class helper for TJSONObject

注意:类和记录Helpers不支持运算符重载。
可以定义多个辅助helpers(助手)并将其与单个类型关联。但是,只有零个或一个helpers(助手)起作用,这决定于助手定义的单元引入的位置。类或记录助手作用域是以正常的Delphi方式确定的(例如,在单元的uses子句中从右到左)。

三、定义Helpers(助手)

下面的代码演示类助手的声明(记录助手的行为方式相同):

type
    TMyClass = class
       procedure MyProc;
       function  MyFunc: Integer;
    end;
 
    ...
 
    procedure TMyClass.MyProc;
    var X: Integer;
    begin
       X := MyFunc;
    end;
 
    function TMyClass.MyFunc: Integer;
    begin
        ...
    end;
 
 ...
 
 type
    TMyClassHelper = class helper for TMyClass
      procedure HelloWorld;
      function MyFunc: Integer;
    end;
 
    ...
 
    procedure TMyClassHelper.HelloWorld;
    begin
       Writeln(Self.ClassName); // Self refers to TMyClass type, not TMyClassHelper
    end;
 
    function TMyClassHelper.MyFunc: Integer;
    begin
      ...
    end;
 
 ...
 
 var
   X: TMyClass;
 begin
   X := TMyClass.Create;
   X.MyProc;    // 调用 TMyClass.MyProc
   X.HelloWorld; // 调用 TMyClassHelper.HelloWorld
   X.MyFunc;    // 调用 TMyClassHelper.MyFunc

提示:请记住,调用类助手函数MyFunc是因为类助手优先于实际的类类型。

总结

1. Helpers语法定义:TJSONObjectHelper = class helper for TJSONObject

2.定义好Helper单元后,需要在使用的单元中引用,Helper(助手)才会起作用;

3.Helper是一种类的扩展方法,但不是设计时使用的方法,原始设计应该始终依赖于普通的类继承和接口实现。

附: helpers(助手)实际应用

A、Delphi原生的JSON操作助手实现

使用Delphi的朋友都知道,三方JSON处理单元SuperObject.pas非常有名气,特别是操作JSON对象的方法非常简单。例如:jo.S[‘Name’] := ‘sensor’,或者 i := jo.I[‘age’],非常方便。但是delphi原生的操作起来,代码就多很多,例如:jo.TryGetValue(‘Name’,js),才能取出值,书写的代码比较多,繁琐,那么通过给TJSONObject 增加一个Helper(助手)就可以实现和SuperObject一样的操作方法。

S[]:表示字符串
I[]:表示整型数
I64[]:表示int63
D[]:表示日期
A[]:表示数组
O[]:表示TJSONObject对象
B[]:表示逻辑值

TJSONObject 的Helper 单元:
{**************************************
时间:2021-06-18
功能:1 实现delphi原生的JSON操作为 S[] 操作方式
作者:sensor
}
unit uSZHN_JSON;

interface
uses
  //System.Classes,
  //System.Types,
  //System.DateUtil,
  //System.Generics.Collections,
  //System.SysUtils,
  System.JSON;

type
  TJSONObjectHelper = class helper for TJSONObject
    private
       function  Get_ValueS(PairName : string) : string;
       procedure Set_ValueS(PairName,PairValue : string);

       function  Get_ValueI(PairName : string) : Integer;
       procedure Set_ValueI(PairName : string; PairValue : Integer);

       function  Get_ValueI64(PairName : string) : Int64;
       procedure Set_ValueI64(PairName : string; PairValue : Int64);

       function  Get_ValueD(PairName : string) : TDateTime;
       procedure Set_ValueD(PairName : string; PairValue : TDateTime);

       function  Get_ValueB(PairName : string) : Boolean;
       procedure Set_ValueB(PairName : string; PairValue : Boolean);

       function  Get_ValueA(PairName : string) : TJSONArray;
       procedure Set_ValueA(PairName : string; PairValue : TJSONArray);

       function  Get_ValueO(PairName : string) : TJSONObject;
       procedure Set_ValueO(PairName : string; PairValue : TJSONObject);

    public
      //判断某个字段是否存在
      function PairExists(PairName : string) : Boolean;

      //定义字段读取函数
      property S[PairName : string] : string      read Get_ValueS   write Set_ValueS;
      property I[PairName : string] : integer     read Get_ValueI   write Set_ValueI;
      property I64[PairName : string] : Int64     read Get_ValueI64 write Set_ValueI64;
      property D[PairName : string] : TDateTime   read Get_ValueD   write Set_ValueD;
      property B[PairName : string] : Boolean     read Get_ValueB   write Set_ValueB;
      property A[PairName : string] : TJSONArray  read Get_ValueA   write Set_ValueA;
      property O[PairName : string] : TJSONObject read Get_ValueO   write Set_ValueO;
  end;

implementation

{ TJSONObjectHelper }



function TJSONObjectHelper.Get_ValueS(PairName: string): string;
var
  js : TJSONString;
begin
  if PairName = '' then  Exit;

  if Self.TryGetValue(PairName,js) then
     Result := js.Value
  else
     Result := '';
end;

function TJSONObjectHelper.PairExists(PairName: string): Boolean;
begin
  Result := Self.Values[PairName] <> nil;
end;

procedure TJSONObjectHelper.Set_ValueS(PairName, PairValue: string);
var
  js : TJSONString;
begin
  //1. 首先查找有没有该字段, 如果有,则直接删除
  if Self.TryGetValue(PairName,js) then
     begin
       Self.RemovePair(PairName).Free; //如果没有free,就会产生内存泄露
     end;
  //2. 然后在增加
  Self.AddPair(PairName, PairValue);
end;

function TJSONObjectHelper.Get_ValueI(PairName: string): Integer;
var
  ji : TJSONNumber;
begin
  if PairName = '' then  Exit(0);

  if Self.TryGetValue(PairName,ji) then
     Result := ji.AsInt
  else
     Result := 0;
end;

procedure TJSONObjectHelper.Set_ValueI(PairName: string; PairValue: Integer);
var
  jn : TJSONNumber;
begin
  //1. 首先查找有没有该字段, 如果有,则直接删除
  if Self.TryGetValue(PairName,jn) then
     Self.RemovePair(PairName).Free;
  //2. 然后在增加
  Self.AddPair(PairName, TJSONNumber.Create(PairValue));
end;

function TJSONObjectHelper.Get_ValueD(PairName: string): TDateTime;
var
  ji : TJSONNumber;
begin
  if PairName = '' then  Exit(0);

  if Self.TryGetValue(PairName,ji) then
     Result := ji.AsDouble
  else
     Result := 0;
end;

procedure TJSONObjectHelper.Set_ValueD(PairName: string; PairValue: TDateTime);
var
  jn : TJSONNumber;
begin
  //1. 首先查找有没有该字段, 如果有,则直接删除
  if Self.TryGetValue(PairName,jn) then
     Self.RemovePair(PairName).Free;
  Self.AddPair(PairName, TJSONNumber.Create(PairValue));
end;


function TJSONObjectHelper.Get_ValueB(PairName: string): Boolean;
var
  jb : TJSONBool;
begin
  if PairName = '' then  Exit(False);

  if Self.TryGetValue(PairName,jb) then
     Result := jb.AsBoolean
  else
     Result := False;
end;

procedure TJSONObjectHelper.Set_ValueB(PairName: string; PairValue: Boolean);
var
  jb : TJSONBool;
begin
  //1. 首先查找有没有该字段, 如果有,则直接删除
  if Self.TryGetValue(PairName,jb) then
     Self.RemovePair(PairName).Free;
  Self.AddPair(PairName, TJSONBool.Create(PairValue));
end;


function TJSONObjectHelper.Get_ValueI64(PairName: string): Int64;
var
  ji : TJSONNumber;
begin
  if PairName = '' then  Exit(0);

  if Self.TryGetValue(PairName,ji) then
     Result := ji.AsInt64
  else
     Result := 0;
end;


procedure TJSONObjectHelper.Set_ValueI64(PairName: string; PairValue: Int64);
var
  jn : TJSONNumber;
begin
  //1. 首先查找有没有该字段, 如果有,则直接删除
  if Self.TryGetValue(PairName,jn) then
     Self.RemovePair(PairName).Free;
  Self.AddPair(PairName, TJSONNumber.Create(PairValue));
end;





function TJSONObjectHelper.Get_ValueA(PairName: string): TJSONArray;
var
  ja : TJSONArray;
begin
  if PairName = '' then  Exit(nil);

  Self.TryGetValue(PairName,Result);
end;





procedure TJSONObjectHelper.Set_ValueA(PairName: string; PairValue: TJSONArray);
var
  ja : TJSONArray;
begin
  //1. 首先查找有没有该字段, 如果有,则直接删除
  if Self.TryGetValue(PairName,ja) then
     Self.RemovePair(PairName).Free;

  Self.AddPair(PairName, PairValue);
end;


function TJSONObjectHelper.Get_ValueO(PairName: string): TJSONObject;
var
  jo : TJSONObject;
begin
  if PairName = '' then  Exit(nil);

  if Self.TryGetValue(PairName,jo) then
     Result := jo
  else
     Result := nil;
end;

procedure TJSONObjectHelper.Set_ValueO(PairName: string; PairValue: TJSONObject);
var
  jo : TJSONObject;
begin
  //1. 首先查找有没有该字段, 如果有,则直接删除
  if Self.TryGetValue(PairName,jo) then
     Self.RemovePair(PairName).Free;
  Self.AddPair(PairName, PairValue as TJSONObject);
end;

end.
使用样例:
uses
	.....
	uSZHN_JSON;

function TForm1.Create_JSON: string;
var
 jo,jo1 : TJSONObject;
 ja : TJSONArray;

begin
  jo  := TJSONObject.Create;
  jo1  := TJSONObject.Create;
  //ja := TJSONArray.Create;
  try
    jo.S['Name'] := 'sensor';
    jo.S['Name'] := 'sensor11';   //重复字段,内容以最后一个为准


    jo.I['age']  := 54;
    jo.I['age']  := 64;	//按照最后一个

    jo.D['birth'] := now;
    jo.B['worked']:= True;
    jo.I64['money'] := $7FF1F2F3F4F5F6F7;  //大数据


    jo.O['OBJ'] := TJSONObject.Create;
    jo.O['OBJ'].S['AAAA'] := '1200';

    jo.O['jjoo11'] := jo1;
    jo1.AddPair('ABC','ABC1000');


    jo.a['ArrayDemo'] := TJSONArray.Create;;
    jo.a['ArrayDemo'].Add('中国');
    jo.a['ArrayDemo'].Add(100);
    jo.a['ArrayDemo'].Add('wwww');
    jo.a['ArrayDemo'].Add(true);

    Result := jo.ToString;
  finally
    jo.Free;  //释放只需要释放jo就可以,其他的会自动释放(包括jo1)

  end;
end;

看完本片文章后,你能否实现将TFDQuery也Helper,让其操作也能使用S[]模式,而不在是FieldByName的模式!减少代码编写量!

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海纳老吴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值