Tbpgr Blog

Employee Experience Engineer tbpgr(てぃーびー) のブログ

書籍 Refactoring to Patterns | Generalization| Form Template Method

パンくず

書籍 Patterns to Patterns
Generalization
Form Template Method

概要

Form Template Methodのリファクタリングについて

使用する場面

サブクラスに変数となる箇所と非変数となる箇所が混ざっている場合、非変数となる箇所はサブクラスで重複している。
Template Methodでリファクタリングすることで、サブクラスの重複をスーパークラスの汎用化したアルゴリズムに移動する。

対応方法

Template Methodを適用する。
Template Methodはアルゴリズムの変数となる箇所をサブクラスで実装する。

利点と欠点

利点

・サブクラスの重複をスーパークラスに移動すること。
・共通のアルゴリズムのステップによる効果的なコミュニケーションを可能にする
・サブクラスでアルゴリズムをカスタマイズするのを容易にする

欠点

・サブクラスがアルゴリズムを満たすために多くのメソッドを実装しなければならない場合、設計が複雑になる

手順

1.階層に似たメソッドを見つける。
(サブクラス同士が似たような手順の処理をしている)
似たようなメソッドにCompose Methodを適用し、
各クラスでシグニチャが同じクラス(Idential Class)と異なるクラス(Unique Class)を抽出する
Unique Methodを抽象メソッドにする

2.Idential MethodにPull Up Methodを適用し、スーパークラスに移動する

3.Uniqueクラス内の似たメソッドに、Rename Methodを適用する。
各サブクラス分これを繰り返す。

4.似たメソッドが、既にサブクラスになくなった場合、
同一のシグニチャを適用するためにRename Methodを適用します。

5.各似たメソッドにPull up Methodを適用し、スーパークラスに抽象メソッド
各サブクラスで実装する。

サンプル

リファクタリング
# encoding: Windows-31J

# 原則として全ての人は起きて、通勤して、働いて、通勤して、帰宅して、
# 自由時間を過ごして就寝するとします

class Tanaka
  def initialize(name);@name=name;end
  def act_day()
    puts "#{@name}の一日"
    puts "起床"
    puts "通勤"
    puts "労働"
    puts "通勤"
    puts "帰宅"
    puts "本を読む" # ここだけ独自処理
    puts "就寝"
  end
end

class Suzuki
  def initialize(name);@name=name;end
  def act_day()
    puts "#{@name}の一日"
    puts "起床"
    puts "通勤"
    puts "労働"
    puts "通勤"
    puts "帰宅"
    puts "ゲームをする" # ここだけ独自処理
    puts "就寝"
  end
end

[Tanaka.new("tanaka"), Suzuki.new("suzuki")].each {|person|person.act_day}
リファクタリング
# encoding: Windows-31J

# 原則として全ての人は起きて、通勤して、働いて、通勤して、帰宅して、
# 自由時間を過ごして就寝するとします

module Person
  def initialize(name);@name=name;end
  def act_day
    puts "#{@name}の一日"
    puts "起床"
    puts "通勤"
    puts "労働"
    puts "通勤"
    puts "帰宅"
    act_free
    puts "就寝"
  end
end

class Tanaka
  include Person
  def act_free();puts "本を読む";end
end

class Suzuki
  include Person
  def act_free();puts "ゲームをする";end
end

class Fuguta
  include Person
end

[Tanaka.new("tanaka"), Suzuki.new("suzuki")].each {|person|person.act_day}
出力
■tanakaの一日
起床
通勤
労働
通勤
帰宅
本を読む
就寝
■suzukiの一日
起床
通勤
労働
通勤
帰宅
ゲームをする
就寝