Rendre le code Delphi plus lisible à l'aide des aides de classe:
Appel classique:
StoreDataset ( 1 , mysqlDataSet, true);Call plus lisible:
mysqlDataSet.StoreSelected_StopAfterFirstError(
function():boolean
begin
Result := mysqlDataSet.FieldByName( ' Status ' ). Value = ' 1 '
end ), fDataStorer);TBYTES HELPER - Générer des nombres, ZLIB Compress, 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 HELPER : Stockez et chargez les TBytes à partir du flux ou du fichier. Chargez et vérifiez l'image 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 Helper : Informations sur 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 HELPER : 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 helper : remplissez et redimensionnez 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 ;Aiders RTL:
| Unité | Description de l'aide |
|---|---|
| Helper.tbytes | Permet de manipuler les tableaux d'octets: taille, chargement et sauvegarde, getter & setters |
| Helper.tdataset | Les fonctionnalités supplémentaires de tdataset comme: itération via l'ensemble de données ou LoadData / Savedata - permet de cartographier une liste d'objets à l'ensemble de données |
| Helper.tdatetime | Méthodes qui permettent de manipuler facilement la date et l'heure |
| Helper.tfield | Permet de charger les données de base64 dans le champ blob ou de vérifier la signature des données stockées |
| Helper.tjsonObject | Méthodes Lire les données ou stocker dans la structure JSON Dom, comme Isvalidisodate (FieldNname) |
| Helper.tstream | Méthodes qui facilitent la lecture et l'écriture de données aux flux |
Aiders VCL:
| Classe élargie | Description de l'aide |
|---|---|
| Tapplication | Échantillon d'assistance contenant une méthode expérimentale comme: InDeveloperMode . |
| Tdbgrid | Méthodes Manipuler les colonnes DBGrid, comme: AutosizEColonnes - Arrangement automatiquement avec chaque colonne |
| Toform | Méthodes Gestion des minuteries: setInterval et setTimeout |
| Tpicture | Permettre d'attribuer des TBytes et Tblobfield à TpiCture avec une reconnaissance automatique du format d'image |
| Tstringgrid | Remplissage et configuration du contrôle de la grille de chaîne: chargement de données, réglage des colonnes largeur, compensation du contenu de la cellule ou de la ligne |
| Twincontrol | Méthodes d'utilité pour rechercher des contrôles enfants par type ou par nom. Visible pour tous les descendants TwinControl: TFORM, TPANEL, etc. |
Autres aides:
| Classe élargie | Description de l'aide |
|---|---|
| Helper.tfdconnection | |
| Helper.tfdcustomManager |
La convention de dénomination desiliaire consiste à ajouter Suffix Helper au nom de la classe élargie, ce qui signifie que l'assistance de classe pour TDataSet aura un nom TDataSetHelper .
Chaque assistant est stocké dans un fichier séparé et unité son nom est Helper.<ExpanedClassName>.pas .
Toutes les unités d'assistance sont stockées dans le sous-dossier src - allez à cet emplacement.
examples/01-playground/ - Aller à cet emplacementHelperPlayground.dprHelper.TStringGrid.pasHelper.TDataSet.pas et Helper.TDBGrid.pasHelper.TBytes.pas et Helper.TStream.pasexamples/02-formhelper/ - Aller à cet emplacementHelpersMiniDemo.dprHelper.TForm.pas et utilisation de Timer A Helper MéthodesL'énorme quantité de code VCL (FMX) peut être effacée à l'aide des aides de classe, qui sont en fait une technique de refactorisation facile avec un faible risque de projets complexes. En utilisant cette méthode, les équipes peuvent commencer à mettre à niveau leurs projets hérités même sans filet de sécurité des tests unitaires. De plus, la vérification des aides nouvellement créées peut être facilement effectuée avec des tests unitaires. Cette approche permet d'enseigner aux développeurs comment écrire des tests unitaires de manière correcte (apprenez dans la pratique des premiers principes ou autres). Les équipes peuvent également appliquer facilement le processus de développement TDD (écrire d'abord les tests, puis implémenter les fonctionnalités) de manière amusante et non invasive.
Parfois, les assistants de classe pourraient également être dangereux s'ils sont mal utilisés. Pour cette raison, il est nécessaire d'appliquer un processus de développement et de livraison un peu plus discipliné, les suggestions liées à cette zone sont couvertes dans les sections suivantes.
Avantages des aides de classe:
Dès le début (Delphi 2006) jusqu'à la version Delphi Berlin / 10.1, le bogue d'assistance de classe était très populaire, qui permet d'accéder aux champs privés et aux méthodes privées à l'aide d'aides. En raison de ce bug, de nombreux développeurs ont identifié cette extension de langue intéressante avec un tel hack. L'utilisation abusive des aides de classe a provoqué que cette valeur de cette solution super puissante est sous-estimée.
L'un des objectifs importants de l'utilisation des aides de classe est la capacité d'extraire du code utile et réutilisable, puis de les couvrir avec des tests unitaires. Les développeurs peuvent même facilement utiliser un TDD, une approche axée sur les tests dans laquelle nous devons d'abord rédiger des tests unitaires, puis implémenter la logique
Ce référentiel montre comment pratiquer l'approche TDD. Chaque classe et assistance enregistrée ont un test Dunitx. Les ensembles de tests unitaires peuvent être facilement élargis pour fournir une meilleure couverture de test. Pour avoir une meilleure expérience de test unitaire, il est recommandé d'installer le meilleur TDD Delphi IDE Extension Tessindsight - gratuit et une plate-forme très productive créée par Stefan Glienke. Gloire à l'auteur! Lien vers le Repo Teshinsight: Accédez au site Bitbucket
Un exemple de test unitaire peut être trouvé dans le dossier du référentiel tests - accédez à cet emplacement
Exemple de test de la méthode ColsWidth de classe de classe TStringGrid :
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 ;Les aides de classe semblent vraiment prometteurs dans la mendicité et en fait, il existe une excellente solution, mais lorsque vous créez et en utilisez de plus en plus, vous commencerez à remarquer certains obstacles. Pour cette raison, les bonnes pratiques devraient être adaptées dès le début pour éviter les problèmes potentiels.
L'une des pratiques recommandées lors de l'utilisation des aides de classe est de planifier une bonne maintenance du projet, y compris le contrôle des versions et la gestion des versions. Étapes éprouvées, y compris deux points importants:
Ce projet GitHub est un exemple en direct de ces techniques de déploiement. Nous utilisons un modèle de ramification inspiré du billet de blog de Vincent Driessen: un modèle de branchement GIT réussi ainsi que le modèle de planification et de livraison inspiré de la méthode Kanban.
Modèle de ramification du projet des aides de classe

is021-grid-column-restore est pour une nouvelle fonctionnalité: Méthode LoadColumnsFromJsonString dans l'assistance de classe TDBGrid, qui permet de restaurer la configuration de la colonne (ordre, légende de titre, largeur et visibilité) stockées dans la chaîne JSON. La définition des fonctionnalités est écrite dans GitHub Numéro # 21is014-doc-dark-side est une nouvelle section de documentation dans le fichier README.md principal.Class Helers Project Kanban Board

Des séances de conseil d'administration et de planification de Kanban sont des techniques suggérées pour atteindre - une livraison incrémentielle. Le projet des aides de classe ne peut pas être livré trop souvent, en raison du coût d'intégration (référentiel d'aide à la classe d'intégration avec les projets finaux de Delphi). Et de l'autre côté, la livraison de la nouvelle version ne devrait pas prendre trop de temps, car tous les projets devraient utiliser les avantages des nouveaux aides (haute réutilisabilité).
Les assistants de classe sont vraiment beaux lors du premier contact, mais ils ont des effets secondaires dangereux. Dans cette section, vous pouvez mieux comprendre les faiblesses de cette solution. Si vous essayez de définir deux assistants de classe en élargissant la même classe de base, vous verrez qu'un seul d'entre eux sera visible. Plus à cela, vous n'êtes pas en mesure d'élargir la fonctionnalité desiliaires de classe avec l'héritage. Vous ne pouvez pas non plus définir une mémoire (champs) supplémentaire dans l'assistance de classe.
Vous pouvez protéger votre projet contre les effets de ces faiblesses. Avant de définir un nouvel assistant de classe, vous devriez vous poser quelques questions:
TButton ) pas pour plus général ( TControl , TComponent , etc.).