Template Method 【Delphi De Design Pattern】

コンテンツ
  • 必要性の指標
  • 状況
  • 方法
  • 結果
  • サンプルコード
  • テストコード
  • 注意事項

必要性の指標

   頻度:★★★
重要度:★★★

状況

  • アルゴリズムが変更される可能性がある
  • アルゴリズムに共通する部分がある
  • 構造はそのままに、アルゴリズムだけ入れ替えたい

方法

  1. 構造や変更のないメソッドの実装を、上位クラスで行なう
  2. 変更可能性のあるメソッドの実装を、下位クラスで行なう

構造や変更のないメソッドをテンプレートと呼ぶ。
変更可能性のあるメソッドをフックと呼ぶ。

すなわち、
テンプレートは、上位クラスで実装し、
フックは、下位クラスで実装する、

こととなる。

  1. フックをあらかじめ、上位クラスで宣言しておく
  2. フックを呼び出すメソッドを、上位クラスで実装する
フックを呼び出すメソッドを、テンプレートメソッドという。

すなわち、
あらかじめ上位クラスで実装したものを、
下位クラスですり替える、
こととなる。


結果


  • 下位クラスで、メソッドに変更を加えられる。
  • 上位クラスで実装したメソッドに対して、変更が適用される。

サンプルコード

  • TAbstract  :上位クラス
  • TConcreate :下位クラス
  • 上位クラスTAbstructの、hookOperationでは、空の文字列を返している
  • 下位クラスTConcreateの、hookOperationでは、入力された文字列をそのまま返している



// NOTE =============================================
// Title      : TemplateMethod
// =================================================
// License    : MIT
// Author     : Penguin-Works
// Make       : 2013/08/04
// Finish     : 2013/08/04
// LastSave   : 2013/08/04
// =================================================
//

unit TemplateMethodUnit ;

interface

  type
    TAbstract = class// --------------------------------------------------------

      published
        function TemplateMethod( _str : string ):string ;

      protected
        function hookOperation( _str : string ) :string ; virtual ;

    end ;

    TConcreate = class( TAbstract )// ------------------------------------------

      protected
        function hookOperation( _str : string ) :string ; override ;
    end ;

implementation

  /// //////////////////////////////////////////////////////////////////////////
  { TAbstract }

  function TAbstract.TemplateMethod( _str : string ): string ;
  // ================================================  
  // Template Method
  // ================================================  
   begin
    // Call Hook Operation
    Result := hookOperation( _str ) ;
  end ;

  function TAbstract.hookOperation( _str : string ): string ;
  // ================================================  
  // Oparation Method
  // ================================================  
   begin
    Result := '' ;
  end ;

  /// //////////////////////////////////////////////////////////////////////////
  { TConcreate }

  function TConcreate.hookOperation( _str : string ): string ;
  // ================================================
  //
  // ================================================
  begin
    Result := _str ;
  end ;

end.



テストコード

  • TestTConcreate.TestTemplateMethod でテストをしている
  • 文字列helloを、TConcreate.TemplateMethodに、入力している
  • hookOperationの変更が反映されるならば、helloが返される。
  • 反映されなければ、空の文字列が返される。
  • テストコードでは、返り値が
    • 空の文字列でないか?
    • 入力した文字列と一致するか?
    を確認している。
  • 実行すると、上記テストがクリアできることを確認できる。


unit TestTemplateMethodUnit ;
{

  Delphi DUnit テスト ケース
  ----------------------
}

interface

  uses
    TestFramework ,
    TemplateMethodUnit ;

  type
    // クラスのテスト メソッド TConcreate

    TestTConcreate = class( TTestCase )
      strict private
        FConcreate : TConcreate ;
      public
        procedure SetUp ; override ;
        procedure TearDown ; override ;
      published
        procedure TestTemplateMethod ;
    end ;

implementation

  procedure TestTConcreate.SetUp ;
  begin
    FConcreate := TConcreate.Create ;
  end ;

  procedure TestTConcreate.TearDown ;
  begin
    FConcreate.Free ;
    FConcreate := nil ;
  end ;

  procedure TestTConcreate.TestTemplateMethod ;
  const
    _nil : string = '' ;
  var
    _expect : string ;
    _result : string ;
  begin

    _expect := 'hello' ;
    _result := _nil ;

    _result := FConcreate.TemplateMethod( _expect ) ;

    CheckNotEqualsString( _nil , _result ) ;
    CheckEqualsString( _expect , _result ) ;

  end ;

initialization

  // テスト ケースをテスト ランナーに登録する
  RegisterTest( TestTConcreate.Suite ) ;

end.

注意事項

TConcreate.hookOperationにある、
overrideは、overloadと間違えやすい。
  • overrideは再定義、(上書きなのでride)
  • overloadは多重定義(同じ名前をいくつも呼びだすのでload)
となる。