クラスを使用した変換の管理

提供: RAD Studio
移動先: 案内検索

計量単位の変換 への移動


変換関数を使用すると、必ず変換単位を登録できます。 ただし、そのために、基本的に同じことを行う関数を不必要に多数作成しなければならなくなる場合があります。

パラメータや変数の値のみ異なる一連の変換関数を作成できる場合は、それらの変換を処理するクラスを作成できます。 たとえば、欧州通貨の場合、ユーロの導入以後、さまざまな欧州通貨間の変換を行うための一連の標準手法が用意されています。 (たとえばドルとユーロの間の変換係数とは異なり)たとえ変換係数がそのまま変わらないとしても、単純な変換係数を使用するアプローチで欧州通貨間の変換を正しく行うことはできません。その理由は以下の 2 点です。

  • 変換結果の丸めの桁数が通貨によって異なる。
  • 変換係数を使用するアプローチでは、ユーロ変換基準で指定されている係数の逆数を係数として使用する。

しかし、これは、以下のような変換関数によりすべて処理できます。

Delphi:

 function FromEuro(const AValue: Double, Factor; FRound: TRoundToRange): Double;
 begin
   Result := RoundTo(AValue * Factor, FRound);
 end;
 function ToEuro(const AValue: Double, Factor): Double;
 begin
   Result := AValue / Factor;
 end;

C++:

double __fastcall FromEuro(const double AValue, const double Factor,
    TRoundToRange FRound) {
    return(RoundTo(AValue * Factor, FRound));
}

double __fastcall ToEuro(const double AValue, const double Factor) {
    return (AValue / Factor);
}

問題は、このアプローチでは変換関数にパラメータが新たに必要になることです。つまり、どの欧州通貨についても同じ関数を登録するだけで済むというわけにはいきません。 欧州通貨ごとに新しい変換関数を 2 つずつ作成する手間を避けるには、それと同じ 2 つの関数を、あるクラスのメンバにすることで利用できます。

変換クラスの作成

このクラスは TConvTypeFactor の下位クラスでなければなりません。TConvTypeFactor には、ToCommonFromCommon の 2 つのメソッドが定義されており、それぞれ、変換ファミリの基本単位への変換と基本単位からの変換(この例ではユーロとの間の変換)を行います。変換単位の登録時に直接使用する関数の場合と同様に、これらのメソッドにも追加のパラメータはないため、丸めの桁数や変換係数を、作成する変換クラスの private メンバとして用意する必要があります。以下は、demos\ConvertIt ディレクトリに含まれている EuroConv サンプル(euroconv.pas を参照)からの抜粋です。

Delphi:

 type
 TConvTypeEuroFactor = class(TConvTypeFactor)
 private
 FRound: TRoundToRange;
 public
 constructor Create(const AConvFamily: TConvFamily;
 const ADescription: string; const AFactor: Double;
 const ARound: TRoundToRange);
 function ToCommon(const AValue: Double): Double; override;
 function FromCommon(const AValue: Double): Double; override;
 end;
 end;

C++:

class PASCALIMPLEMENTATION TConvTypeEuroFactor
		: public Convutils::TConvTypeFactor {
private:
	TRoundToRange FRound;

public:
	__fastcall TConvTypeEuroFactor(const TConvFamily AConvFamily,
			const AnsiString ADescription, const double AFactor,
			const TRoundToRange ARound);
	TConvTypeFactor(AConvFamily, ADescription, AFactor);
	virtual double ToCommon(const double AValue);
	virtual double FromCommon(const double AValue);
}

以下のように、コンストラクタで private メンバに値が割り当てられます。

Delphi:

 constructor TConvTypeEuroFactor.Create(const AConvFamily: TConvFamily; const ADescription: string; const AFactor: Double; const ARound: TRoundToRange);
 begin
   inherited Create(AConvFamily, ADescription, AFactor);
   FRound := ARound;
 end;

C++:

__fastcall TConvTypeEuroFactor::TConvTypeEuroFactor
    (const TConvFamily AConvFamily, const AnsiString ADescription,
    const double AFactor, const TRoundToRange ARound)
    : TConvTypeFactor(AConvFamily, ADescription, AFactor); {
    FRound = ARound;
}

以下のように、2 つの変換関数は上記の private メンバを使用するだけです。

Delphi:

 function TConvTypeEuroFactor.FromCommon(const AValue: Double): Double;
 begin
   Result := RoundTo(AValue * Factor, FRound);
 end;
 function TConvTypeEuroFactor.ToCommon(const AValue: Double): Double;
 begin
   Result := AValue / Factor;
 end;

C++:

virtual double TConvTypeEuroFactor::ToCommon(const double AValue) {
    return (RoundTo(AValue * Factor, FRound));
}

virtual double TConvTypeEuroFactor::ToCommon(const double AValue) {
    return (AValue / Factor);
}

変数の宣言

これで変換クラスができたので、他のあらゆる変換ファミリの場合と同様に、まず識別子を宣言します。

Delphi:

 var
   euEUR: TConvType; { EU euro }
 euBEF: TConvType; { Belgian francs }
 euDEM: TConvType; { German marks }
 euGRD: TConvType; { Greek drachmas }
 euESP: TConvType; { Spanish pesetas }
 euFFR: TConvType; { French francs }
 euIEP: TConvType; { Irish pounds }
 euITL: TConvType; { Italian lire }
 euLUF: TConvType; { Luxembourg francs }
 euNLG: TConvType; { Dutch guilders }
 euATS: TConvType; { Austrian schillings }
 euPTE: TConvType; { Portuguese escudos }
 euFIM: TConvType; { Finnish marks }
   cbEuro: TConvFamily;

C++:

TConvFamily cbEuro;
TConvType euEUR; // EU euro
TConvType euBEF; // Belgian francs
TConvType euDEM; // German marks
TConvType euGRD; // Greek drachmas
TConvType euESP; // Spanish pesetas
TConvType euFFR; // French francs
TConvType euIEP; // Irish pounds
TConvType euITL; // Italian lire
TConvType euLUF; // Luxembourg francs
TConvType euNLG; // Dutch guilders
TConvType euATS; // Austrian schillings
TConvType euPTE; // Protuguese escudos
TConvType euFIM; // Finnish marks

変換ファミリと他の単位の登録

これで、新規作成した変換クラスを使って、変換ファミリと欧州通貨単位を登録する用意ができました。他の変換ファミリの登録と同じように、この変換ファミリを登録します。

Delphi:

 cbEuro := RegisterConversionFamily ('European currency');

C++:

cbEuro = RegisterConversionFamily("European currency");

各変換型を登録するには、以下のように、その通貨の係数と丸めのプロパティを反映した変換クラスのインスタンスを作成し、RegisterConversionType メソッドを呼び出します。

Delphi:

 var
   LInfo: TConvTypeInfo;
 begin
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'EUEuro', 1.0, -2);
   if not RegisterConversionType(LInfo, euEUR) then
     LInfo.Free;
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'BelgianFrancs', 40.3399, 0);
   if not RegisterConversionType(LInfo, euBEF) then
     LInfo.Free;
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'GermanMarks', 1.95583, -2);
   if not RegisterConversionType(LInfo, euDEM) then
     LInfo.Free;
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'GreekDrachmas', 340.75, 0);
   if not RegisterConversionType(LInfo, euGRD) then
     LInfo.Free;
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'SpanishPesetas', 166.386, 0);
   if not RegisterConversionType(LInfo, euESP) then
     LInfo.Free;
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'FrenchFrancs', 6.55957, -2);
   if not RegisterConversionType(LInfo, euFFR) then
     LInfo.Free;
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'IrishPounds', 0.787564, -2);
   if not RegisterConversionType(LInfo, euIEP) then
     LInfo.Free;
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'ItalianLire', 1936.27, 0);
   if not RegisterConversionType(LInfo, euITL) then
     LInfo.Free;
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'LuxembourgFrancs', 40.3399, -2);
   if not RegisterConversionType(LInfo, euLUF) then
     LInfo.Free;
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'DutchGuilders', 2.20371, -2);
   if not RegisterConversionType(LInfo, euNLG) then
     LInfo.Free;
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'AustrianSchillings', 13.7603, -2);
   if not RegisterConversionType(LInfo, euATS) then
     LInfo.Free;
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'PortugueseEscudos', 200.482, -2);
   if not RegisterConversionType(LInfo, euPTE) then
     LInfo.Free;
   LInfo := TConvTypeEuroFactor.Create(cbEuro, 'FinnishMarks', 5.94573, 0);
   if not RegisterConversionType(LInfo, euFIM) then
     LInfo.Free;
 end;

C++:

TConvTypeInfo *pInfo = new TConvTypeEuroFactor(cbEuro, " EUEuro ", 1.0, -2);
if (!RegisterConversionType(pInfo, euEUR))
	delete pInfo;
pInfo = new TConvTypeEuroFactor(cbEuro, " BelgianFrancs ", 40.3399, 0);
if (!RegisterConversionType(pInfo, euBEF))
	delete pInfo;
pInfo = new TConvTypeEuroFactor(cbEuro, " GermanMarks ", 1.95583, -2);
if (!RegisterConversionType(pInfo, euDEM))
	delete pInfo;
pInfo = new TConvTypeEuroFactor(cbEuro, " GreekDrachmas ", 340.75, 0);
if (!RegisterConversionType(pInfo, euGRD) delete pInfo;
pInfo = new TConvTypeEuroFactor(cbEuro, " SpanishPesetas ", 166.386, 0);
if (!RegisterConversionType(pInfo, euESP) delete pInfo;
pInfo = new TConvTypeEuroFactor(cbEuro, " FrenchFrancs ", 6.55957, -2);
if (!RegisterConversionType(pInfo, euFFR) delete pInfo;
pInfo = new TConvTypeEuroFactor(cbEuro, " IrishPounds ", 0.787564, -2);
if (!RegisterConversionType(pInfo, euIEP) delete pInfo;
pInfo = new TConvTypeEuroFactor(cbEuro, " ItalianLire ", 1936.27, 0);
if (!RegisterConversionType(pInfo, euITL) delete pInfo;
pInfo = new TConvTypeEuroFactor(cbEuro, " LuxembourgFrancs ", 40.3399, -2);
if (!RegisterConversionType(pInfo, euLUF) delete pInfo;
pInfo = new TConvTypeEuroFactor(cbEuro, " DutchGuilders ", 2.20371, -2);
if (!RegisterConversionType(pInfo, euNLG) delete pInfo;
pInfo = new TConvTypeEuroFactor(cbEuro, " AutstrianSchillings ", 13.7603, -2);
if (!RegisterConversionType(pInfo, euATS) delete pInfo;
pInfo = new TConvTypeEuroFactor(cbEuro, " PortugueseEscudos ", 200.482, -2);
if (!RegisterConversionType(pInfo, euPTE) delete pInfo;
pInfo = new TConvTypeEuroFactor(cbEuro, " FinnishMarks ", 5.94573, 0);
if (!RegisterConversionType(pInfo, euFIM) delete pInfo;

メモ: [スタート|プログラム|Embarcadero RAD Studio Sydney|サンプル] をクリックすると、ConvertIt サンプルを見ることができます(Object Pascal\RTL\ConvertIt および \CPP\RTL\ConvertIt を参照)。ConvertIt サンプルは、この例を拡張したもので、変換レートが固定ではない他の通貨に対応しているほか、エラー チェックも追加されています。

新しい単位の使用

これで、新規登録した単位を使用して、アプリケーションで変換を実行できます。新規の cbEuro 変換ファミリに登録した欧州通貨単位どうしであれば、その間の変換はグローバル関数 Convert で実行できます。たとえば、以下のコードでは、値をイタリア リラからドイツ マルクに変換しています。

C++:

Edit2->Text = FloatToStr(Convert(StrToFloat(Edit1->Text), euITL, euDEM));

関連項目