クラスヘルパーを使用して、Delphiコードをより読みやすくする:
クラシックコール:
StoreDataset ( 1 , mysqlDataSet, true);より読みやすい通話:
mysqlDataSet.StoreSelected_StopAfterFirstError(
function():boolean
begin
Result := mysqlDataSet.FieldByName( ' Status ' ). Value = ' 1 '
end ), fDataStorer);tbytesヘルパー- 数字、Zlibコンプレッズ、base64エンコード、計算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ヘルパー:ストリームまたはファイルからTBYTEを保存およびロードします。 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ヘルパー:
| ユニット | ヘルパーの説明 |
|---|---|
| helper.tbytes | バイトの配列を操作できます:サイズ、ロード&セーブ、ゲッター&セッター |
| helper.tdataset | 次のような追加のtdataset機能:データセットまたはloaddata / savedataを繰り返します - オブジェクトのリストをデータセットにマッピングできます |
| helper.tdateTime | 日付と時刻を簡単に操作できる方法 |
| helper.tfield | base64データをブロブフィールドにロードするか、保存されたデータの署名の検証を許可します |
| helper.tjsonobject | Isvalidisodate(FieldName)などのJSON DOM構造にデータを読み取るか、JSON DOM構造に保存する方法 |
| helper.tstream | データの読み取りと書き込みを容易にする方法ストリーム |
VCLヘルパー:
| 拡張クラス | ヘルパーの説明 |
|---|---|
| タップリケーション | InDeveloperModeのような実験方法を含むサンプルヘルパー。 |
| tdbgrid | 次のようなdbgrid列を操作する方法:autosizecolumns-各列に自動的に配置する |
| tform | タイマーの管理方法:SetIntervalおよびSettimeOut |
| tpicture | 自動イメージ形式の認識でtbytesとtblobfieldをtpictureに割り当てることを許可します |
| tstringgrid | 文字列グリッド制御の充填と構成:データの読み込み、列の幅の設定、セルまたは行の内容のクリア |
| Twincontrol | タイプまたは名前で子のコントロールを検索するためのユーティリティ方法。すべてのTwincontrolの子孫に見える:Tform、Tpanelなど。 |
他のヘルパー:
| 拡張クラス | ヘルパーの説明 |
|---|---|
| helper.tfdconnection | |
| helper.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バージョンまで、非常に人気のあるクラスヘルパーバグがあり、ヘルパーを使用してプライベートフィールドやプライベートメソッドにアクセスできます。このバグのために、多くの開発者はこのようなハックでこの興味深い言語拡張機能を特定しました。クラスヘルパーの誤用は、この非常に強力なソリューションの価値を過小評価しています。
クラスヘルパーを使用する重要な目的の1つは、有用で再利用可能なコードを抽出する能力であり、それらを単体テストでカバーすることです。開発者は、最初にユニットテストを作成してからロジックを実装する必要があるTDD、テスト駆動型アプローチを簡単に使用できます。
そのリポジトリは、TDDアプローチを練習する方法を示しています。各クラスとレコードヘルパーにはDunitxテストがあります。ユニットテストセットを簡単に拡張して、より良いテストカバレッジを提供できます。より良いユニットテストの経験を持つために、最高のTDD Delphi IDE Extension 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 ;クラスのヘルパーは物ggingいで本当に有望に見え、実際には素晴らしい解決策がありますが、それらをますます多く使用すると、いくつかの障害に気付くようになります。このため、潜在的な問題を回避するために、優れた慣行を最初から調整する必要があります。
クラスヘルパーを使用する際の推奨されるプラクティスの1つは、バージョン制御やリリース管理など、優れたプロジェクトメンテナンスを計画することです。 2つの重要なポイントを含む実績のあるステップ:
このGitHubプロジェクトは、このような展開技術のライブ例です。 Vincent Driessenに触発された分岐モデルを使用しています。ブログ投稿:成功したGit分岐モデルと、Kanban Methodに触発されたPlaning and Deliveryモデル。
クラスヘルパープロジェクト分岐モデル

is021-grid-column-restore 、JSON文字列に保存されている列構成(注文、タイトルキャプション、幅、可視性)を復元できるTDBGridクラスヘルパーでのメソッドLoadColumnsFromJsonStringフロムフロムフロムの新機能用です。機能定義は、Github Issue#21で書かれていますis014-doc-dark-sideは、メインREADME.mdファイルの新しいドキュメントセクションです。クラスヘルパープロジェクトカンバンボード

カンバンボードと計画セッションは、達成するために推奨されるテクニック - 増分配信です。クラスヘルパープロジェクトは、統合コスト(統合クラスヘルパーリポジトリと最終的なDelphiプロジェクト)のため、あまり頻繁に配信できません。また、新しいバージョンの反対側の配信から、すべてのプロジェクトが新しいヘルパーの利点を使用する必要があるため、それほど時間はかかりません(高い再利用性)。
クラスのヘルパーは最初の連絡先で本当に見栄えがしますが、危険な副作用があります。このセクションでは、このソリューションの弱点をよりよく理解することができます。同じ基本クラスを拡張する2つのクラスのヘルパーを定義しようとすると、そのうちの1つだけが表示されることがわかります。さらに、継承でクラスヘルパー機能を拡大することはできません。また、クラスヘルパーの追加メモリ(フィールド)を定義することもできません。
これらの弱点の影響からプロジェクトを保護できます。新しいクラスヘルパーを定義する前に、いくつかの質問をする必要があります。
TButton )のヘルパーを定義します( TControl 、 TComponentなど)。