7

インターフェースを使用する理由に関する Nick Hodges のブログを興味深く読みまし た。私はコーディングのより高いレベルでのインターフェースが大好きなので、これを非常に低いレベルに拡張する方法を調べ、どのサポートがサポートされているかを調査することにしました。これは VCL クラスに存在するためです。

私が必要とする一般的な構造は、TStringList で簡単なことを行うことです。たとえば、次のコードは小さなテキスト ファイル リストをコンマ テキスト文字列にロードします。

var
  MyList : TStrings;
  sCommaText : string;
begin
  MyList := TStringList.Create;
  try
    MyList.LoadFromFile( 'c:\temp\somefile.txt' );
    sCommaText := MyList.CommaText;

    // ... do something with sCommaText.....

  finally
    MyList.Free;
  end;
end;

MyList をインターフェイスとして使用して記述できれば、かなり単純化されているように思えます。それにより、try-finally が取り除かれ、読みやすさが向上します。

var
  MyList : IStrings;
         //^^^^^^^
  sCommaText : string;
begin
  MyList := TStringList.Create;
  MyList.LoadFromFile( 'c:\temp\somefile.txt' );
  sCommaText := MyList.CommaText;

  // ... do something with sCommaText.....

end;

ただし、IStrings が定義されているのを確認できません。オンラインで OLE プログラミングに関連して参照されていますが、Classes.pas にはありません。それは存在しますか?これは有効な単純化ですか?Delphi XE2 を使用しています。

4

2 に答える 2

6

RTL/VCL には、必要なことを行うインターフェイスはありません ( と同じインターフェイスを公開しますTStrings)。そのようなものを使用したい場合は、自分で発明する必要があります。

次のようなラッパーで実装します。

type
  IStrings = interface
    function Add(const S: string): Integer;
  end;

  TIStrings = class(TInterfacedObject, IStrings)
  private
    FStrings: TStrings;
  public
    constructor Create(Strings: TStrings);
    destructor Destroy; override;
    function Add(const S: string): Integer;
  end;

constructor TIStrings.Create(Strings: TStrings);
begin
  inherited Create;
  FStrings := Strings;
end;

destructor TIStrings.Destroy;
begin
  FStrings.Free; // don't use FreeAndNil because Nick might see this code ;-)
  inherited;
end;

function TIStrings.Add(const S: string): Integer;
begin
  Result := FStrings.Add(S);
end;

当然、インターフェイスの残りの部分をTStrings実際のクラスにラップします。このようなラッパー クラスTStringsを使用して、そのインスタンスにアクセスするだけで任意の型をラップできるようにします。

次のように使用します。

var
  MyList : IStrings;
....
MyList := TIStrings.Create(TStringList.Create);

ヘルパー関数を追加して、 を呼び出すという面倒な作業を実際に行うことをお勧めしますTIStrings.Create

寿命が問題になる可能性があることにも注意してください。TStrings基礎となるインスタンスの有効期間の管理を引き継がない、このラッパーのバリアントが必要になる場合があります。これは、TIStringsコンストラクターのパラメーターで調整できます。


私自身、これは興味深い思考実験だと思いますが、実際には賢明なアプローチではありません。クラスは、TStringsインターフェイスが提供するほとんどすべての利点を持つ抽象クラスです。そのまま使うデメリットは特にないと思います。

于 2012-02-01T12:43:20.620 に答える
4

は抽象クラスであるためTStrings、そのインターフェース バージョンはあまり提供しません。TStringsとにかく、そのインターフェースの実装者は確実に子孫になるでしょうTStringsTStringsインターフェイスが必要な理由は 2 つあります。

  1. 自動リソース クリーンアップTStringsそのために固有のインターフェースは必要ありません。代わりに、ISafeGuardJCL からのインターフェースを使用してください。次に例を示します。

    var
      G: ISafeGuard;
      MyList: TStrings;
      sCommaText: string;
    begin
      MyList := TStrings(Guard(TStringList.Create, G));
    
      MyList.LoadFromFile('c:\temp\somefile.txt');
      sCommaText := MyList.CommaText;
    
      // ... do something with sCommaText.....
    end;
    

    同じ存続期間を持つ複数のオブジェクトを保護するには、 を使用しますIMultiSafeGuard

  2. 外部モジュールとの相互運用。これがIStrings目的です。Delphiは、既存の子孫TStringsAdapterを呼び出すときに返されるクラスでそれを実装します。文字列リストがあり、期待またはインターフェースする別のモジュールへのアクセスを許可する必要がある場合に使用します。これらのインターフェースは、それ以外の場合は使いにくいです — どちらもすべてのものを提供していません — そのため、必要がない限り使用しないでください。GetOleStringsTStringsIStringsIEnumStringTStrings

    使用している外部モジュールが、モジュールがコンパイルされたのと同じ Delphi バージョンで常にコンパイルされることを保証TStringsできるものである場合は、実行時パッケージを使用して子孫を直接渡す必要があります。共有パッケージにより、両方のモジュールがクラスの同じ定義を使用できるようになり、メモリ管理が大幅に簡素化されます。

于 2012-02-01T14:35:42.037 に答える