Tbpgr Blog

Ruby プログラマ tbpgr(てぃーびー) のブログ

書籍 リファクタリング−プログラマーの体質改善 | オブジェクト間での特性の移動 | クラスの抽出:Extract Class

内容

リファクタリング

クラスの抽出:Extract Class

適用ケース要約

2つのクラスで行うべき仕事をしている1個のクラスがある。

適用内容要約

新しいクラスを作成し、関連フィールド、メソッドを旧クラスから新クラスに移す。

適用詳細

クラス内の処理を拡張していくにつれ、一つ以上の役割を果たすクラスになっていまい
責務があいまいになった際などにクラスの抽出が有効です。

サンプル

通常のコーディングとテストクラスのコーディングとテストの実施を実装します。

サンプルコード

リファクタリング

# encoding: Shift_JIS

class Coding
  attr_accessor:class_name,:method_list,:test_class_name,:test_method_list

  def initialize(class_name,method_list)
    @class_name=class_name
    @method_list=method_list
    @test_class_name="Test#{class_name}"
    @test_method_list=Array.new
    @method_list.each {|method|
      method="test#{method.capitalize}"
      @test_method_list.push method
    }
  end

  def coding()
    puts "#{class_name}のコーディングを開始"
    @method_list.each{|method|
      puts "#{method}メソッドのの実装完了"
    }
    puts "#{class_name}のコーディングを完了"
    puts "---------------------------------"
  end
  
  def test_coding()
    puts "#{test_class_name}のコーディングを開始"
    @test_method_list.each{|method|
      puts "#{method}メソッドのの実装完了"
    }
    puts "#{class_name}のコーディングを完了"
    puts "---------------------------------"
  end
  def test()
    puts "#{test_class_name}のテストを開始"
    @test_method_list.each{|method|
      puts "#{method}メソッドのテスト完了"
    }
    puts "#{test_class_name}のテストを完了"
    puts "---------------------------------"
  end
end

coding=Coding.new("Hoge",["method1","method2"])
coding.coding
coding.test_coding
coding.test

リファクタリング

# encoding: Shift_JIS

class Coding
  attr_accessor:klass,:test_class

  def initialize(class_name,method_list)
    @klass=Klass.new(class_name,method_list)

    test_method_list=Array.new
    @klass.method_list.each {|method|
      method="test#{method.capitalize}"
      test_method_list.push method
    }
    @test_class=TestClass.new("Test#{class_name}",test_method_list)
  end

  def coding()
    klass.coding
  end
  
  def test_coding()
    test_class.coding
  end
  
  def test()
    test_class.test
  end
end

class Klass
  attr_accessor:class_name,:method_list
  
  def initialize(class_name,method_list)
    @class_name=class_name
    @method_list=method_list
  end

  def coding()
    puts "#{class_name}のコーディングを開始"
    @method_list.each{|method|
      puts "#{method}メソッドの実装完了"
    }
    puts "#{class_name}のコーディングを完了"
    puts "---------------------------------"
  end
end

class TestClass < Klass
  def test()
    puts "#{class_name}のテストを開始"
    @method_list.each{|method|
      puts "#{method}メソッドのテスト完了"
    }
    puts "#{class_name}のテストを完了"
    puts "---------------------------------"
  end
end

coding=Coding.new("Hoge",["method1","method2"])
coding.coding
coding.test_coding
coding.test

▼出力結果(共通)

Hogeのコーディングを開始
method1メソッドの実装完了
method2メソッドの実装完了
Hogeのコーディングを完了
---------------------------------
TestHogeのコーディングを開始
testMethod1メソッドの実装完了
testMethod2メソッドの実装完了
TestHogeのコーディングを完了
---------------------------------
TestHogeのテストを開始
testMethod1メソッドのテスト完了
testMethod2メソッドのテスト完了
TestHogeのテストを完了
---------------------------------
解説

コーディングを行うクラスであるCodingに
Classをあらわす情報、TestClassをあらわす情報が混在していたため
これをクラスとして抽出しました。