类和记录的 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的模式!减少代码编写量!