DelphiでRAII

Delphiのインターフェースを使うと、参照カウントが0になったオブジェクトは自動で破棄されます。
この機能を使って、変数がスコープを離れた時にリソースを返却するRAIIを実現できます。

次のサンプルプログラムは、ボタンを押した時に時間のかかる処理を行います。
処理中はカーソルを砂時計にして、処理が終わったらカーソルを元に戻します。

procedure TForm1.Button1Click(Sender: TObject);
var
  Save_Cursor: TCursor;
begin
  Save_Cursor := Screen.Cursor; //現在のカール祖を保存
  Screen.Cursor := crHourGlass; //カーソルを砂時計に変更
  try
    Sleep(5000);  //時間のかかる処理
  finally
    Screen.Cursor := Save_Cursor; //カーソルを元に戻す
  end;
end;

RAIIを使うと、次のようなコードを書くことができます。
コードがずいぶんと見やすくなります。

procedure TForm1.Button2Click(Sender: TObject);
var
  Cursor: IRAIICursor;
begin
  Cursor := CreateRAIICursor(crHourGlass); //カーソルを砂時計に変更
  Sleep(5000);  //時間のかかる処理
end;  //スコープを離れるとカーソルを元に戻す

実装方法は次のようになります。

type
  /// <summary>カーソルを管理するRAIIのインターフェース</summary>
  IRAIICursor = interface
  end;

  /// <summary>RAIIのオブジェクトを取得する</summary>
  /// <param name="Cursor">変更するカーソル</param>
  /// <returns>RAIIのオブジェクト。実体はTRAIICursorクラス</returns>
  function CreateRAIICursor(Cursor: TCursor):IRAIICursor;

implementation

type
  /// <summary>IRAIICursorの実装。このクラスは公開しない。</summary>
  TRAIICursor = class(TInterfacedObject, IRAIICursor)
  private
    FCursor: TCursor; //変更前のカーソル
  public
    constructor Create(Cursor: TCursor);
    destructor Destroy; override;
  end;

constructor TRAIICursor.Create(Cursor: TCursor);
begin
  FCursor := Screen.Cursor;
  Screen.Cursor := Cursor;
end;

destructor TRAIICursor.Destroy;
begin
  Screen.Cursor := FCursor; //カーソルを元に戻す
end;

function CreateRAIICursor(Cursor: TCursor):IRAIICursor;
begin
  Result := TRAIICursor.Create(Cursor);
end;

なかなか便利ではないかと思いますが、いかがでしょうか。

コメント

  1. こんにちは。
    以下のような利用例でもOKでしょうか?

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    CreateRAIICursor(crHourGlass);
    Sleep(2000);
    end;

  2. 高橋智宏様
    ありがとうございます。
    変数に代入しなくてもいいのですね。
    ちょっと不思議な気もします。
    勉強になりました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です