III. Fonction Convert▲
C'est la fonction globale Convert qui réalise la conversion. La valeur à convertir est de type double et le résultat fourni est également de type double.
On peut faire appel à la fonction Convert dès lors que les familles et unités de mesure sont recensées.
Nous allons reprendre le premier exemple pour comprendre le fonctionnement. Rappelons que la fonction Convert est définie deux fois avec des paramètres différents (directive overload) :
III-A. Première définition de Convert (conversion simple)▲
La ligne de code suivante :
miles := Convert(metres, duMeters, duMiles);
appelle la première définition de Convert, soit une conversion simple. Voyons le détail du code exécuté :
function
Convert(const
AValue: Double
; const
AFrom, ATo: TConvType): Double
;
var
LFromTypeInfo, LToTypeInfo: TConvTypeInfo;
begin
if
not
GetConvInfo(AFrom, ATo, LFromTypeInfo, LToTypeInfo) then
RaiseConversionError(SConvIncompatibleTypes2,
[ConvTypeToDescription(AFrom),
ConvTypeToDescription(ATo)]);
Result := LToTypeInfo.FromCommon(LFromTypeInfo.ToCommon(AValue));
end
;
On commence par un appel à GetConvInfo. On passe en paramètre le type de l'unité de mesure source (AFrom) et destination (ATo) et on obtiendra en retour les objets TConvInfo (fig. 9) respectifs (dans LFromTypeInfo et LToTypeInfo). Cela va permettre, à partir des références (nombres entiers) des unités recensées de retrouver les objets de type TConvInfo respectifs, car ce sont eux qui implémentent la conversion.
Si GetConvInfo a réussi, alors le calcul de la conversion réside dans l'appel des méthodes FromCommon et ToCommon des objets TConvTypeInfo précédemment retrouvés.
Ce sont les méthodes de TConvTypeFactor (descendant de TConvInfo) qui sont appelées, car les types d'unités de mesure metres et miles ont été recensés avec un facteur multiplicateur (fig. 10).
FFromTypeInfo.ToCommon(AValue) est calculé en premier, voici l'implémentation VCL :
function
TConvTypeFactor.ToCommon(const
AValue: Double
): Double
;
begin
Result := AValue * FFactor;
end
;
Et le résultat est ensuite passé à LToTypeInfo.FromCommon(le résultat de 3.) :
function
TConvTypeFactor.FromCommon(const
AValue: Double
): Double
;
begin
Result := AValue / FFactor;
end
;
Le double appel :
Result := LToTypeInfo.FromCommon(LFromTypeInfo.ToCommon(AValue));
correspond dans notre exemple au calcul :
Resultat := AValue * Facteur mètres / Facteur miles;
La VCL convertit la mesure initiale vers l'unité de mesure commune pour ensuite la convertir vers l'unité de mesure finale ce qui est logique puisque toutes les unités de mesure possèdent un facteur de conversion lié à l'unité de mesure commune.
Lors du recensement, la VCL prend connaissance du facteur de conversion entre toutes les unités de mesure recensées et l'unité de mesure commune de la même famille. FFactor est un attribut privé (accédé par la propriété Factor) qui mémorise le facteur de conversion de l'unité de mesure respective par rapport à l'unité de mesure commune (unité dont le facteur = 1).
La fig. 11 explique comment fonctionne la VCL pour convertir une mesure vers une autre en spécifiant qu'elle passe par une étape intermédiaire : la conversion vers l'unité de mesure commune.
III-B. Deuxième définition de Convert (conversion procédurale)▲
Le fonctionnement dans le cadre d'une conversion procédurale est quasi identique. Voyons avec un exemple de conversion performance --> points de l'épreuve de perche du décathlon (que l'on retrouvera en détail plus loin).
duPerfPerche et duPointDecation sont des pointeurs de fonctions de type TConversionProc dont la déclaration est la suivante :
TConversionProc = function
(const
AValue: Double
): Double
;
L'exécution de la conversion s'effectuera comme suit :
points := Convert(perf, duPerfPerche, duPointDecathlon);
La fonction Convert est appelée comme précédemment, une différence subsiste au moment de
Result := LToTypeInfo.FromCommon(LFromTypeInfo.ToCommon(AValue));
Le type duPerfPerche a été recensé en créant un objet non plus de type TConvTypeFactor, mais de type TConvTypeProcs (voir fig. 12). La différence est que les fonctions ToCommon et FromCommon ne sont pas implémentées dans cette classe, mais déléguées à des fonctions fournies par le développeur (stockées dans les propriétés privées FToCommonProc et FFromCommonProc au moment du recensement) :
decaPerche := RegisterConversionType(cbDecathlon, 'Perf Perche'
, PerfPercheToPoints, PointsToPerfPerche);
Ici, FToCommonProc référence la fonction PerfPercheToPoints et FFromCommonProc référence la fonction PointsToPerfPerche.
On retrouve la redirection d'appel à ces fonctions dans l'implémentation de ToCommon et de FromCommon :
function
TConvTypeProcs.ToCommon(const
AValue: Double
): Double
;
begin
Result := FToCommonProc(AValue);
end
;
function
TConvTypeProcs.FromCommon(const
AValue: Double
): Double
;
begin
Result := FFromCommonProc(AValue);
end
;
Diagramme de classes :
Nous avons maintenant suffisamment de connaissances pour créer un système de conversions personnalisées.