使用类助手使Delphi代码更可读:
经典电话:
StoreDataset ( 1 , mysqlDataSet, true);更可读的通话:
mysqlDataSet.StoreSelected_StopAfterFirstError(
function():boolean
begin
Result := mysqlDataSet.FieldByName( ' Status ' ). Value = ' 1 '
end ), fDataStorer);tbytes助手- 生成数字,zlib压缩,base64 encode,calc crc32
uses
Helpers.TBytes;
type
TUploadImageCommand = record
Image: string;
ControlSum: integer;
end ;
procedure SendCommandToRestServer ( const aCommand: TUploadImageCommand);
begin
writeln( ' Use RestClient or IdHttpClient to send POST request ' );
writeln( ' POST /rest/upload-image/ TUploadImageCommand ' );
writeln( ' TUploadImageCommand: ' );
writeln( ' ControlSum = ' , aCommand.ControlSum);
writeln( ' Image Length = ' , Length(aCommand.Image));
writeln( ' Image = ' , aCommand.Image);
end ;
var
bytes: TBytes;
idx: integer;
memoryStream: TMemoryStream;
command := TUploadImageCommand;
begin
bytes.Size := 1000 ;
for idx := 0 to bytes.Size- 1 do
bytes[idx] := idx div 10 ;
memoryStream := TMemoryStream.Create();
bytes := CompressToStream(memoryStream);
command.Image := bytes.GenerateBase64Code();
command.ControlSum := bytes.GetSectorCRC32( 0 , bytes.Size);
SendCommandToRestServer(command);
end .Tbytes助手:从流或文件中存储和加载tbytes。加载和验证PNG图像
uses
Helpers.TBytes;
var
bytes: TBytes;
idx: integer;
memoryStream: TMemoryStream;
command := TUploadImageCommand;
begin
bytes.InitialiseFromBase64String( ' U2FtcGxlIHRleHQ= ' );
bytes.SaveToFile( ' notes.txt ' ); // save: Sample text
memoryStream:= bytes.CreateStream();
// memoryStream.Size = 11
memoryStream.Free;
// -----------------
s := bytes.GetSectorAsString( 0 , 6 ); // ASCII only text
bytes := [ 0 , 0 , 15 , 16 , $A0, 255 , 0 , 0 , 0 , 0 , 1 ];
if bytes.GetSectorAsHex( 2 , 4 ) = ' 0F 10 A0 FF ' then
begin
memoryStream := TMemoryStream.Create();
memoryStream.LoadFromFile( ' small.png ' );
memoryStream.Position := 0 ;
signature.LoadFromStream(memoryStream, 8 );
if (signature.GetSectorAsHex = ' 89 50 4E 47 0D 0A 1A 0A ' ) and
(signature.GetSectorAsString( 1 , 3 ) = ' PNG ' ) then
begin
memoryStream.Position := 0 ;
pngImage := TPngImage.Create;
pngImage.LoadFromStream(memoryStream);
// Image1.Picture := pngImage;
pngImage.Free;
end ;
memoryStream.Free;
end ;
end ;TDATETIME助手:有关TDATETIME的信息
uses
Helpers.TDateTime;
var
date: TDateTime;
begin
date := EncodeDate( 1989 , 06 , 04 );
writeln(date.AsYear); // 1989
writeln(date.AsMonth); // 06
writeln(date); // 06/04/1989
writeln(EncodeDate( 2017 , 10 , 24 ).DayOfWeek); // 3
writeln(date.IncMonth( 5 ).ToString( ' yyyy-mm-dd ' ); // 1989-11-04
writeln(date.AsStringDateISO); // 1989-06-04
date := EncodeDate( 2019 , 10 , 24 ) + EncodeTime( 18 , 45 , 12 , 0 );
writeln(date.AsStringDateISO); // 2019-10-24T18:45:12.000Z
end .tdataset助手:foreachrow,loaddata <>,savedata <>
uses
Helpers.TDataSet;
type
TCity = class
public
id: Integer;
City: string;
Rank: Variant;
visited: Variant;
end ;
var
dataset: TDataSet;
cityNames: TArray<string>;
idx: integer;
cities: TObjectList<TCityForDataset>;
begin
dataset := GivenDataSet(fOwner, [
{ } [ 1 , ' Edinburgh ' , 5.5 , EncodeDate( 2018 , 05 , 28 )],
{ } [ 2 , ' Glassgow ' , 4.5 , EncodeDate( 2015 , 09 , 13 )],
{ } [ 3 , ' Cracow ' , 6.0 , EncodeDate( 2019 , 01 , 01 )],
{ } [ 4 , ' Prague ' , 4.9 , EncodeDate( 2013 , 06 , 21 )]]);
SetLength(cityNames, dataset.RecordCount);
idx := 0 ;
dataset.ForEachRow(
procedure
begin
cityNames[idx] := dataset.FieldByName( ' city ' ).AsString;
inc(idx);
end );
writeln(string.Join( ' , ' , citiecityNamess));
cities := dataset.LoadData<TCityForDataset>();
witeln(cities.Count); // 4
witeln(cities[ 0 ].City); // Edinburgh
witeln(cities[ 3 ].Rank); // 4.9
cities[ 2 ].Rank := 5.8 ;
cities[ 2 ].visited := EncodeDate( 2020 , 7 , 22 );
cities.Add(TCity.Create());
cities[ 4 ].id := 5 ;
cities[ 4 ].City := ' Warsaw ' ;
dataset.SaveData<TCity>(cities);
// SaveData updated Cracow record and added Warsaw
endTSTRINGGRID助手:填充和调整大小tstringgrid
// StringGrid1: TStringGrid;
// StringGrid2: TStringGrid;
procedure TForm1.Button1Click (Sender: TObject);
var
structure, rows: string;
begin
StringGrid1.ColCount := 4 ;
StringGrid1.RowCount := 3 ;
StringGrid1.ColsWidth([ 40 , 100 , 90 , 110 , 80 ]);
StringGrid1.FillCells([
[ ' 1 ' , ' Jonh Black ' , ' U21 ' , ' 34 ' ],
[ ' 2 ' , ' Bogdan Polak ' , ' N47 ' , ' 28 ' ]]);
structure :=
' {"column": "no", "caption": "No.", "width": 30}, ' +
' {"column": "mesure", "caption": "Mesure description", "width": 200}, ' +
' {"column": "value", "caption": "Value", "width": 60} ' ;
rows :=
' {"no": 1, "mesure": "Number of DI Containers", "value": 120}, ' +
' {"no": 2, "mesure": "Maximum ctor injection", "value": 56} ' ;
data
jsData := TJSONObject.ParseJSONValue(Format(
' {"structure": [%s], "data": [%s]} ' , [structure, rows])
) as TJSONObject;
StringGrid2.FillWithJson(jsData);
end ;RTL帮助者:
| 单元 | 助手描述 |
|---|---|
| 助手 | 允许操纵字节数组:大小,加载和保存,Getter&Setters |
| 助手 | 其他TDATASET功能,例如:通过数据集或LoadData / savedata进行迭代 - 允许将对象列表映射到数据集 |
| 助手 | 允许轻松操纵日期和时间的方法 |
| 助手 | 允许将base64数据加载到blob字段或验证存储数据的签名 |
| 助手 | 方法读取数据或存储在JSON DOM结构中,例如Isvalidisodate(fieldName) |
| 助手 | 有助于阅读和写入数据的方法 |
VCL帮助者:
| 扩展的班级 | 助手描述 |
|---|---|
| tapplication | 含有实验方法的样品辅助器,例如: InDeveloperMode 。 |
| TDBGRID | 操纵DBGRID列的方法,例如:Autosizecolumns-自动与每一列安排 |
| tform | 方法管理计时器:setInterval和settimeout |
| tpicture | 允许使用自动图像格式识别分配TBytes和Tblobfield到Tpicture |
| TSTRINGGRID | 填充和配置字符串网格控制:加载数据,设置列宽度,清除单元格或行的内容 |
| Twincontrol | 用类型或按名称搜索子控件的实用方法。所有双感染后代都可以看到:tform,tpanel等。 |
其他帮助者:
| 扩展的班级 | 助手描述 |
|---|---|
| 助手。tfdConnection | |
| 助手。tfdcustommanager |
助手命名约定是在扩展的类的名称中添加后缀Helper ,这意味着TDataSet的类助手将具有TDataSetHelper的名称。
每个助手都存储在一个单独的文件中,并且单元的名称为Helper.<ExpanedClassName>.pas 。
所有助手单元都存储在src子文件夹中 - 转到该位置。
examples/01-playground/ - 转到该位置HelperPlayground.dprHelper.TStringGrid.pasHelper.TDataSet.pas和Helper.TDBGrid.pasHelper.TBytes.pas和Helper.TStream.pasexamples/02-formhelper/ - 转到该位置HelpersMiniDemo.dprHelper.TForm.pas和计时器的用法可以使用类助手清除大量的VCL(FMX)代码,这实际上是一种容易的重构技术,对复杂项目的风险较低。使用这种方法,即使没有单位测试安全网,团队也可以启动升级其旧项目。此外,可以通过单元测试可以轻松地对新创建的帮助者进行验证。这种方法允许教授开发人员如何以正确的方式编写单元测试(在实践中学习第一原则或其他原则)。团队还可以轻松地以有趣且无创的方式应用TDD开发过程(首先编写测试,然后实现功能)。
有时,如果不正确地使用班级助手,也可能会很危险。因此,需要应用一些纪律处分的开发和交付过程,以下各节涵盖了与该领域相关的建议。
班级帮助者受益:
从一开始(Delphi 2006)到Delphi Berlin / 10.1版本,就有非常受欢迎的类帮助者错误,它允许使用助手访问私有字段和私人方法。由于这个错误,许多开发人员用这种骇客确定了这种有趣的语言扩展。滥用班级助手导致这种超强大解决方案的价值被低估了。
使用班级助手的重要目的之一是提取有用和可重复使用的代码,然后用单元测试覆盖它们的能力。开发人员甚至可以轻松采用TDD,测试驱动的方法,在该方法中,我们首先需要编写单元测试然后实施逻辑
该存储库正在演示如何练习TDD方法。每个班级和记录助手都有Dunitx测试。单位测试集可以轻松扩展,以提供更好的测试覆盖范围。为了获得更好的单元测试经验,建议安装最佳的TDD Delphi iDE扩展测试IDE Testinsight-免费和由Stefan Glienke创建的非常有生产力的平台。荣耀作者!链接到TestInsight Repo:转到Bitbucket网站
可以在tests存储库中找到样品单元测试 - 转到该位置
TStringGrid类助手ColsWidth方法的样本测试:
procedure TestTStringGridHelper.FiveColumns_ColsWidth ;
begin
fGrid.ColCount := 5 ;
fGrid.ColsWidth([ 50 , 100 , 90 , 110 , 80 ]);
Assert.AreEqual( 110 , fGrid.ColWidths[ 3 ]);
Assert.AreEqual( 80 , fGrid.ColWidths[ 4 ]);
end ;班级助手在乞讨中看起来确实很有希望,实际上有很棒的解决方案,但是当您创建和使用越来越多的方法时,您会开始注意到一些障碍。因此,应从一开始就适应良好的实践,以帮助避免潜在的问题。
使用班级助手的推荐做法之一是计划良好的项目维护,包括版本控制和发布管理。经过验证的步骤,包括两个重要的一点:
这个GitHub项目是此类部署技术的实时示例。我们正在使用受Vincent Driessen博客文章启发的分支模型:成功的GIT分支模型,以及受看板方法启发的计划和交付模型。
班级助手项目分支模型

is021-grid-column-restore用于新功能:TDBGrid类助手中的方法LoadColumnsFromJsonString ,它允许在JSON字符串中还原列配置(顺序,标题字幕,宽度和可见度)。特征定义写在GitHub问题#21中is014-doc-dark-side是Main README.md文件中的新文档部分。班级助手项目看板董事会

斜视董事会和计划会议是建议实现的技术 - 增量交付。由于集成成本(与最终Delphi项目的集成班级辅助存储库),班级帮助者项目不能经常交付。从另一侧交付的新版本不应花费太长时间,因为所有项目都应使用新助手的优势(高可重复使用性)。
班级助手在第一次接触时看起来真的很不错,但是它们具有一些危险的副作用。在本节中,您可以更好地了解该解决方案的弱点。如果您尝试定义两个班级助手,以扩展相同的基类,您会发现只有一个可以看到其中一个。更重要的是,您无法通过继承扩展类帮助器功能。另外,您无法在类帮助器中定义其他内存(字段)。
您可以保护项目免受这些弱点的影响。在定义新的班级帮手之前,您应该问自己几个问题:
TButton )定义助手,则不是更通用的( TControl , TComponent等)。