Tbpgr Blog

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

書籍 リファクタリング−プログラマーの体質改善 | 継承の取り扱い | Template Methodの形成

内容

リファクタリング

Template Methodの形成

適用ケース要約

異なる2つのサブクラスのメソッドが類似の処理を同じ順序で実行しているが、各処理は異なっている

適用内容要約

元のメソッドが同一になるように、各処理を同じシグニチャを持つメソッドにする。
そして、それらを引き上げる。

適用詳細

同じ順序で処理を行い、かつ一部だけ異なるようなクラスが複数ある場合にこのリファクタリングを適用します。
共通部をスーパークラスで定義して、異なる箇所はスーパークラスの抽象メソッドで定義して各継承クラス側で実装します。

サンプル

コードジェネレーターを想定します。このジェネレーターではプロダクトコードとテストコードの両方を生成します。

サンプルコード

リファクタリング

# encoding: Shift_JIS

class GenerateProductCode
  def generate(class_name, method_name)
    result=""
    result << get_class_code(class_name)
    result << get_method_code(method_name)
    result << "end"
    return result
  end
  
  private 
  def get_class_code(class_name)
    return "class #{class_name}\n"
  end
  
  private 
  def get_method_code(method_name)
    return "\tdef #{method_name}()\n\tend\n"
  end
end

class GenerateTestCode
  def generate(class_name, method_name)
    result=""
    result << get_class_code(class_name)
    result << get_method_code(method_name)
    result << "end"
    return result
  end
  
  private 
  def get_class_code(class_name)
    return "class Test#{class_name}\n"
  end
  
  private 
  def get_method_code(method_name)
    return "\tdef test_#{method_name}.()\n\tend\n"
  end
end

generate_product_code = GenerateProductCode.new
puts generate_product_code.generate("Order", "get_order")

generate_test_code = GenerateTestCode.new
puts generate_test_code.generate("Order", "get_order")

リファクタリング

# encoding: Shift_JIS

class CodeGenerator
  def generate(class_name, method_name)
    result=""
    result << get_class_code(class_name)
    result << get_method_code(method_name)
    result << "end"
    return result
  end
end

class GenerateProductCode < CodeGenerator
  private 
  def get_class_code(class_name)
    return "class #{class_name}\n"
  end
  
  private 
  def get_method_code(method_name)
    return "\tdef #{method_name}()\n\tend\n"
  end
end

class GenerateTestCode < CodeGenerator
  private 
  def get_class_code(class_name)
    return "class Test#{class_name}\n"
  end
  
  private 
  def get_method_code(method_name)
    return "\tdef test_#{method_name}.()\n\tend\n"
  end
end

generate_product_code = GenerateProductCode.new
puts generate_product_code.generate("Order", "get_order")

generate_test_code = GenerateTestCode.new
puts generate_test_code.generate("Order", "get_order")

出力(共通)

class Order
	def get_order()
	end
end
class TestOrder
	def test_get_order.()
	end
end