使用類助手使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等)。