unit Myc.Data.Types.Decimal; interface uses Myc.Data.Types; type // Concrete implementation of the IDataDecimalType interface. TImplDataDecimalType = class(TInterfacedObject, IDataDecimalType) private FScale: Integer; strict private class var // Pre-cached instances for scales 0-18. FDecimalTypes: TArray; public constructor Create(const AScale: Integer); class constructor CreateClass; class destructor DestroyClass; // Returns a cached instance for the specified scale. class function GetInstance(const AScale: Integer): IDataDecimalType; static; // IDataType function GetName: String; function GetKind: TDataKind; // IDataDecimalType function GetScale: Integer; function CreateValue(const AValue: Int64): IDataDecimalValue; end; implementation uses System.SysUtils, System.Math; type TDataDecimalValue = class(TInterfacedObject, IDataDecimalValue) private FDataType: IDataDecimalType; FValue: Int64; public constructor Create(const AValue: Int64; const ADataType: IDataDecimalType); // IDataValue function GetDataType: IDataType; function GetAsString: string; // IDataDecimalValue function GetValue: Int64; end; { TImplDataDecimalType } constructor TImplDataDecimalType.Create(const AScale: Integer); begin inherited Create; FScale := AScale; end; class constructor TImplDataDecimalType.CreateClass; var i: Integer; begin // Create and cache singleton instances for each supported scale. SetLength(FDecimalTypes, 19); for i := 0 to High(FDecimalTypes) do FDecimalTypes[i] := TImplDataDecimalType.Create(i); end; class destructor TImplDataDecimalType.DestroyClass; begin FDecimalTypes := nil; end; class function TImplDataDecimalType.GetInstance(const AScale: Integer): IDataDecimalType; begin if (AScale < 0) or (AScale > High(FDecimalTypes)) then raise EArgumentException.CreateFmt('Scale for decimal must be between 0 and %d.', [High(FDecimalTypes)]); Result := FDecimalTypes[AScale]; end; function TImplDataDecimalType.CreateValue(const AValue: Int64): IDataDecimalValue; begin Result := TDataDecimalValue.Create(AValue, Self); end; function TImplDataDecimalType.GetKind: TDataKind; begin Result := dkDecimal; end; function TImplDataDecimalType.GetName: String; begin Result := Format('Decimal(18, %d)', [FScale]); end; function TImplDataDecimalType.GetScale: Integer; begin Result := FScale; end; { TDataDecimalValue } constructor TDataDecimalValue.Create(const AValue: Int64; const ADataType: IDataDecimalType); begin inherited Create; FValue := AValue; FDataType := ADataType; end; function TDataDecimalValue.GetAsString: string; var s: string; scale: Integer; insertPos: Integer; begin s := IntToStr(abs(FValue)); scale := FDataType.Scale; if scale > 0 then begin if Length(s) <= scale then s := StringOfChar('0', scale - Length(s) + 1) + s; insertPos := Length(s) - scale; Result := Copy(s, 1, insertPos) + '.' + Copy(s, insertPos + 1, MaxInt); end else begin Result := s; end; if FValue < 0 then Result := '-' + Result; end; function TDataDecimalValue.GetDataType: IDataType; begin Result := FDataType; end; function TDataDecimalValue.GetValue: Int64; begin Result := FValue; end; end.