パンくず
書籍 Patterns to Patterns
Simplification
Compose Method
概要
Compose Methodのリファクタリングについて
使用する場面
雑然とした長い処理のメソッドなどがある場合
対応方法
同レベルの粒度でExtract Methodを適用する。
役割を表す分かりやすい名前をつけることで、コメントが無くても
各メソッド名を読めば処理の内容が分かるようにする。
利点と欠点
手順
・小さく考える。1メソッドの処理は5から10行を目安にする
・重複を削除し、デッドコードを削除する
・コミュニケーション目的。名前に目的を込める
・単純にする
・粒度を同じにする
サンプル
特に意味のある仕様ではありませんが、幾つかの意味のある処理の塊に対して
手続き的に並べただけの処理を用意します。
リファクタリングにより、細かいメソッドやクラスに分割し
メソッド名を順に読むだけで処理の内容を把握出来るレベルまで落とし込みます。
リファクタリング前
# encoding: Windows-31J #・入力文字列がnilかチェックする #・入力文字列が空文字かチェックする #・入力文字列が100文字以上だったらエラーにする #・カンマで配列に分割する #・各要素に対して以下の処理を行う # ・文字数を取得する # ・文字数が奇数ならodd、偶数ならevenを文字列として追加する #・配列の内容を標準出力する #・oddとevenのどちらが多かったかを比較して返却(1奇数が多い、0同じ、-1偶数が多い) class ComplexClass def complex_method(original) raise 'nil' if original.nil? raise 'empty' if original.empty? raise 'over' if original.length >= 100 original_list = original.split(',') odd_counter = 0 even_counter = 0 original_list.each do |each_data| len = each_data.length each_data << (len.odd? ? "odd":"even") if len.odd? each_data << "odd" odd_counter = odd_counter.succ else each_data << "even" even_counter = even_counter.succ end end return odd_counter <=> even_counter # debug code p original_list end end complex = ComplexClass.new #complex.complex_method nil # => nil error #complex.complex_method empty # => empty error #complex.complex_method "0123456789"*10 # => over error p complex.complex_method "1,12,123,1234,12345" p complex.complex_method "1,12,123,1234" p complex.complex_method "1,12,123,1234,12"
リファクタリング後
# encoding: Windows-31J #・入力文字列がnilかチェックする #・入力文字列が空文字かチェックする #・入力文字列が100文字以上だったらエラーにする #・カンマで配列に分割する #・各要素に対して以下の処理を行う # ・文字数を取得する # ・文字数が奇数ならodd、偶数ならevenを文字列として追加する #・配列の内容を標準出力する #・oddとevenのどちらが多かったかを真偽値で返却する #・oddとevenのどちらが多かったかを比較して返却(1奇数が多い、0同じ、-1偶数が多い) class ComplexClass def complex_method(original) check_original(original) original_list = get_original_list(original) original_list.each {|each_data|each_data << original_list.get_odd_even(each_data)} return original_list.compare_odd_even end def check_original(original) raise 'nil' if original.nil? raise 'empty' if original.empty? raise 'over' if original.length >= 100 end def get_original_list(original);OriginalList.new(original.split(','));end end class OriginalList attr_accessor:original_list,:odd_count,:even_count def initialize(list) @odd_count=0 @even_count=0 @original_list = list end def increment_odd;@odd_count = @odd_count.succ;end def increment_even;@even_count = @even_count.succ;end # イテレーターの実装 def each;@original_list.each{|value|yield(value)};end # 奇数と偶数の数を比較 def compare_odd_even;return @odd_count <=> @even_count;end # 奇数偶数をカウントして奇数なら「odd」、偶数なら「even」を返却 def get_odd_even(original) if original.length.odd? increment_odd return "odd" else increment_even return "even" end end end complex = ComplexClass.new #complex.complex_method nil # => nil error #complex.complex_method empty # => empty error #complex.complex_method "0123456789"*10 # => over error p complex.complex_method "1,12,123,1234,12345" p complex.complex_method "1,12,123,1234" p complex.complex_method "1,12,123,1234,12"
出力内容(共通)
1 0 -1