LoginSignup
0

More than 5 years have passed since last update.

Template Method(テンプレートメソッド)パターン

Last updated at Posted at 2018-12-15

image.png

1つずつデザインパターンをまとめ

総論

パターンそのものと使い所を理解する

Template Method(テンプレートメソッド)パターン

抽象メソッドのアルゴリズムを変更するパターン。
基底クラスに骨格となるメソッド(テンプレートメソッド)と、抽象メソッド(テンプレートメソッドにまとめられるメソッド)を定義し、具象クラスで抽象メソッドをオーバーライドすることで変更に対応するパターン。

Template Methodのテンプレート

super.rb
class スーパークラス

  def initialize(args)
    @args1 = args[:args1]
    @args2 = args[:args2]
  end

  def テンプレートメソッド
    抽象メソッド1
    抽象メソッド2(@args1)
    抽象メソッド3
  end

  # 例のためいくつかのパターンを定義
  def 抽象メソッド1
  end

  def 抽象メソッド2(arg)
    標準実装
  end

  def 抽象メソッド3
    raise 'Called abstract method 抽象メソッド3'
  end
end
sub.rb
require './main'

class サブクラス < スーパークラス
  def 抽象メソッド1
  end

  def 抽象メソッド2(arg)
  end

  def 抽象メソッド3
    オーバーライド
  end
end
main.rb
require './sub'

class Main
  @サブ変数 = サブクラス.new(args1 => 1, args2 => 2)
  @サブ変数.テンプレートメソッド
end

使い所

〇〇を△△毎に□□したい
例) レポートをフォーマット毎に出力したい

  • 「レポートクラス」がスーパークラス、「レポートを出力」をテンプレートメソッドとして定義
  • 「レポートを出力」時に行う基本ステップを抽象メソッドとして定義し、「レポートを出力」内で呼び出すようにする
    • 出力スタート
    • ヘッダ出力
    • ボディ出力スタート
    • ボディ出力
    • ボディ出力終了
    • 出力終了
  • HTMLレポート、プレーンテキストレポート、XMLレポートクラスをサブクラスに定義
  • サブクラス内で基本ステップのメソッドを定義し、個々の実装でオーバーライド
  • 使用したいレポートクラスをインスタンス化し「レポート出力」を呼び出し
  • 各フォーマットにあった文字列が出力

特徴

  • オブジェクト指向における、継承、ポリモーフィズムを活用したもの
    • 継承 -> サブクラスでテンプレートメソッドが呼べる
    • ポリモーフィズム -> 抽象メソッドのロジックがサブクラス毎に変わる
  • デザインパターンの基本系
  • 不変と可変に分離したもの

考え方

  • テンプレートメソッドとは抽象メソッドをまとめたメソッド
  • 抽象メソッドとはアルゴリズムが何をするのかを定義したメソッド
  • スーパークラスの抽象メソッドでは高レベルの処理を制御する
  • スーパークラスの抽象メソッドは実装が空でも良い
  • サブクラスの抽象メソッドはオーバーライドするか標準機能のままか選択余地がある(定義は必須)
  • スーパークラスの抽象メソッドが空のメソッドをサブクラスでも空で定義したものはフックメソッドと呼べる
  • DDDで考えると、テンプレートメソッドはドメインが担うビジネスロジックに相当しそう
  • DDDで考えると、抽象メソッドはビジネスロジック内の処理ステップに相当しそう
  • オブジェクトを初期化するinitializeメソッドも既存のinitializeをオーバーライドしているのでテンプレートメソッドといえる

手順

  1. 実現したい業務命令を担うべきクラスを検討し作成
  2. 業務命令をテンプレートメソッドとして定義
  3. 業務命令によって行う基本の処理ステップを抽象メソッドとして定義
  4. 抽象メソッドのアルゴリズムを実装
  5. 呼び出して実行結果を確認

ポイント

  • 1.の時点で業務命令に汎用性がない場合、スーパクラスかサブクラスかはそこまで意識しなくても良い。
  • 業務命令によって実現するものの種類が複数になり、2.、3.を改めて汎用性があるか検討することで、より適切なテンプレートメソッドや、抽象メソッドを定義できる。
  • そのためテストを作成した方が良い。
  • ただ、ある程度の抽象精度や仕様が不変でないとメインの実装へのオーバーヘッドが大きくなり過ぎてしまうため、最低限の設計が固まってから作成するのが良さそう
  • 「今必要なことだけ行う」を徹底する(解決したい問題に絞って単純なコードを書いていく)

実例

  • WeBrickのGenericServerクラス
  • initializeメソッド

用語整理

  • 基底クラスとほぼ同義
    • 抽象基底クラス
    • 抽象クラス
    • スーパークラス
    • 親クラス
    • AbstractClass

->不変なものといえる

  • 具象クラスとほぼ同義
    • サブクラス
    • 子クラス
    • ConcreteClass

->可変なものといえる

書籍情報

Russ Olsen, Rubyによるデザインパターン
https://amzn.to/2PFKt6m

雑感

プログラミング自体がシステムを作成するための操作を抽象的に言語化したもので、オブジェクト指向やデザインパターンは更に設計手法を抽象化したものであり、更にそれを解釈ベースで言語化するのは大変と感じる。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0