パンくず
書籍 Patterns to Patterns
Creation
Replace Constructors with Creation Method
概要
Replace Constructors with Creation Methodのリファクタリングについて
使用する場面
オーバーロードした多数のコンストラクタが存在し、
クラスを利用する側がどのコンストラクタを利用すればよいのか分かりにくい場面。
このような場合、引数だけでどのコンストラクタを利用するか判断するのは困難であり
紛らわしいコンストラクタが増えるため利用されなくなったコンストラクタなどの発見も
困難になる。
利点と欠点
利点
・どのコンストラクタを利用すればよいか、分かりやすくなる
・同じ引数で別の用途のコンストラクタを持てない、というような通常のコンストラクタの制限にとらわれない
・使われなくなったコンストラクタを発見しやすい
・「Extract Class」や「Extract Subclass」等、さらなるリファクタリングの土台となる
欠点
・標準的なコンスタラクタの生成方法と異なる
手順
1.多数のインスタンスを作り分けるためのコンストラクタを見つける。
コンストラクタの利用側で、生成のロジックに対してpublic staticで「Extract Method」を行う。
こうして作成されたメソッドは「Creation Method」です。
作成したメソッドを生成元のクラス側に「Move Method」で移動します。
2.同種のインスタンスを取得している箇所を全て洗い出して先程作成した「Creation Method」を
参照するように修正します。
3.作成した「Creation Method」が他のコンストラクタを連鎖呼び出ししているだけであれば
メソッドのインライン化によってコンストラクタを削除する。
4.1-3の手順をすべてのコンストラクタに繰り返します。
5.コンストラクタが外部から参照されなくなったらprivete属性に変更します
サンプル
Rubyの場合、そもそもコンストラクタのオーバーロード自体が出来ないので
このようなケース自体発生しない。
仮にRubyで目的別にコンストラクタを作成すると以下のようになる。
# encoding: Windows-31J class ProgrammingLanguage attr_accessor:name def initialize(name) @name = name end def self.create_java return Java.new end def self.create_ruby return Ruby.new end end class Java < ProgrammingLanguage JAVA = "Java" def initialize @name = JAVA end end class Ruby < ProgrammingLanguage RUBY = "Ruby" def initialize @name = RUBY end end languages = [ProgrammingLanguage.create_java,ProgrammingLanguage.create_ruby] languages.each {|language|puts language.name}
出力結果
Java Ruby