Hacer que el código Delphi sea más legible con los ayudantes de clase:
Llamada clásica:
StoreDataset ( 1 , mysqlDataSet, true);Llamada más legible:
mysqlDataSet.StoreSelected_StopAfterFirstError(
function():boolean
begin
Result := mysqlDataSet.FieldByName( ' Status ' ). Value = ' 1 '
end ), fDataStorer);Tbytes Helper - Genere números, Compress de ZLIB, codificación Base64, 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 : almacene y cargue tbytes desde la transmisión o archivo. Cargue y verifique la imagen 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 : Información sobre 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 : llene y redimensione 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 ;Ayudantes de RTL:
| Unidad | Descripción del ayudante |
|---|---|
| Ayudante.tbytes | Permite manipular matrices de bytes: tamaño, carga y guardar, obtener y acomodadores |
| Ayudante.tdataset | Funcionalidad adicional de TDATASET como: iterando a través del conjunto de datos o LoadData / SaveData: permite asignar una lista de objetos al conjunto de datos |
| Ayudante.tdatetime | Métodos que permiten manipular fácilmente la fecha y la hora |
| Ayudante.tfield | Permite cargar datos Base64 en el campo BLOB o verificar la firma de los datos almacenados |
| Helper.tjsonObject | Métodos de lectura de datos o almacenamiento en la estructura JSON DOM, como ISValidisodate (Nombre de campo) |
| Ayudante.tstream | Métodos que facilitan la lectura y la escritura de datos a las transmisiones |
Ayudantes de VCL:
| Clase expandida | Descripción del ayudante |
|---|---|
| Tapplication | Muestra a ayuda de ayuda que contiene un método experimental como: InDeveloperMode . |
| Tdbgrid | Métodos que manipulan columnas DBGRID, como: AutoSizeColumns: organizar automáticamente con cada columna |
| TFORM | Métodos de administración de temporizadores: setInterval y settimeut |
| Tpictor | Permitir asignar tbytes y tblobfield a tpicture con reconocimiento automático de formato de imagen |
| Tstringgrid | Rellenar y configurar el control de la cuadrícula de cadenas: carga de datos, configuración del ancho de las columnas, el contenido de borde de la celda o la fila |
| Twincontrol | Métodos de utilidad para buscar controles para niños por tipo o por nombre. Visible para todos los descendientes de twincontrol: tform, tpanel, etc. |
Otros ayudantes:
| Clase expandida | Descripción del ayudante |
|---|---|
| Helper.tfdconnection | |
| Helper.tfdcustommanager |
La convención de nombres de ayuda es agregar sufijo Helper al nombre de la clase expandida, lo que significa que la clase Helper para TDataSet Will tiene un nombre TDataSetHelper .
Cada ayudante se almacena en un archivo y unidad separados, su nombre es Helper.<ExpanedClassName>.pas .
Todas las unidades auxiliares se almacenan en la subcarpeta src : vaya a esa ubicación.
examples/01-playground/ - Vaya a esa ubicaciónHelperPlayground.dprHelper.TStringGrid.pasHelper.TDataSet.pas y Helper.TDBGrid.pasHelper.TBytes.pas y Helper.TStream.pasexamples/02-formhelper/ - vaya a esa ubicaciónHelpersMiniDemo.dprHelper.TForm.pas y uso del temporizador A Métodos de ayudaLa gran cantidad de código VCL (FMX) se puede borrar utilizando ayudantes de clase, que en realidad son una técnica de refactorización fácil con bajo riesgo para proyectos complejos. Usando este método, los equipos pueden comenzar a actualizar sus proyectos heredados incluso sin una red de seguridad de pruebas unitarias. Además, la verificación de ayudantes recién creados se puede hacer fácilmente con pruebas unitarias. Este enfoque permite enseñar a los desarrolladores cómo escribir pruebas unitarias de manera correcta (aprenda en la práctica los primeros principios u otros). Los equipos también pueden aplicar fácilmente el proceso de desarrollo de TDD (escriba las pruebas primero y luego implementan la funcionalidad) de una manera divertida y no invasiva.
A veces, los ayudantes de clase también podrían ser peligrosos si se usan de manera incorrecta. Por esta razón, se requiere aplicar un proceso de desarrollo y entrega un poco más disciplinado, las sugerencias relacionadas con esa área están cubiertas en las siguientes secciones.
Beneficios de los ayudantes de clase:
Desde el principio (Delphi 2006) hasta la versión de Delphi Berlin / 10.1, había un error de clase de clase bastante popular, que permite acceder a campos privados y métodos privados utilizando ayudantes. Debido a este error, muchos desarrolladores identificaron esta interesante extensión del idioma con tal hack. El mal uso de los ayudantes de clase ha causado ese valor de esta solución súper poderosa se subestima.
Uno de los propósitos importantes del uso de ayudantes de clase es la capacidad de un código de extracto útil y reutilizable, y luego cubrirlos con pruebas unitarias. Los desarrolladores incluso pueden emplear fácilmente el enfoque de TDD, impulsado por las pruebas en el que primero necesitamos escribir pruebas unitarias y luego implementar la lógica
Ese repositorio está demostrando cómo practicar el enfoque TDD. Cada clase y récord de ayuda tiene una prueba Dunitx. Los conjuntos de pruebas unitarias se pueden ampliar fácilmente para proporcionar una mejor cobertura de prueba. Para tener una mejor experiencia de prueba unitaria, se recomienda instalar el mejor TDD Delphi IDE Extension TestInsight : una plataforma gratuita y muy productiva creada por Stefan Glienke. ¡Gloria al autor! Enlace al TestInsight Repo: Vaya al sitio de Bitbucket
La prueba unitaria de muestra se puede encontrar en la carpeta de repositorio tests : vaya a esa ubicación
Prueba de muestra del método ColsWidth de clase 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 ;Los ayudantes de clase se ve realmente prometedor en la mendicidad y en realidad hay una gran solución, pero a medida que crea y usa más y más de ellos, comenzará a notar algunos obstáculos. Por esta razón, las buenas prácticas deben adaptarse desde el principio para ayudar a evitar posibles problemas.
Una de las prácticas recomendadas al usar ayudantes de clase es planificar un buen mantenimiento del proyecto, incluido el control de versiones y la gestión de lanzamientos. Pasos probados que incluyen dos puntos importantes:
Este proyecto GitHub es un ejemplo en vivo de tales técnicas de implementación. Estamos utilizando el modelo de ramificación inspirado en la publicación de blog de Vincent Dressen: un modelo de ramificación GIT exitoso junto con el modelo de planificación y entrega inspirado en el método Kanban.
Modelo de ramificación del proyecto de ayuda de clase

is021-grid-column-restore es para una nueva característica: Método LoadColumnsFromJsonString en TDBGrid Class Helper, que permite restaurar la configuración de columnas (orden, título de título, ancho y visibilidad) almacenado en la cadena JSON. La definición de características está escrita en el número 21 de Githubis014-doc-dark-side es una nueva sección de documentación en el archivo principal README.md .Board Kanban Project Kanban

La junta de Kanban y las sesiones de planificación se sugieren técnicas para lograr: entrega incremental. El proyecto de ayuda de clase no se puede entregar con demasiada frecuencia, debido al costo de integración (repositorio de ayudantes de clase de integración con los proyectos finales de Delphi). Y desde el otro lado, la entrega de la nueva versión no debería llevar demasiado tiempo, porque todos los proyectos deben usar ventajas de nuevos ayudantes (alta reutilización).
Los ayudantes de clase se ven muy bien en el primer contacto, pero tienen algunos efectos secundarios peligrosos. En esta sección puede comprender mejor las debilidades de esta solución. Si intenta definir dos ayudantes de clase que expanden la misma clase base, verá que solo uno de ellos será visible. Más a eso, no puede expandir la funcionalidad auxiliar de clase con herencia. Además, no puede definir memoria adicional (campos) en el ayudante de clase.
Puede proteger su proyecto contra los efectos de estas debilidades. Antes de definir un nuevo ayudante de clase, debe hacerse algunas preguntas:
TButton ) no para más general ( TControl , TComponent , etc.).