こんにちは。
最近 リファクタリング Rubyエディション を読みました。本書はリファクタリングの様々なパターンをRubyのサンプルコードを使って解説している名著です。
実務でも活かせそうなパターンが多くあったので、いいなと思ったパターンを1つずつブログにまとめています。
今回はその第6弾で「コンストラクタからファクトリメソッドへ」についてまとめました。
オリジナルの Ruby のサンプルコードを使って説明しています。
第5弾の「タイプコードからポリモーフィズムへ」のまとめはこちらです。
タイプコードからポリモーフィズムへ【リファクタリング Rubyエディションまとめ5】 - 銀行員からのRailsエンジニア
サンプルコード
リファクタリング前
文章での説明よりもコードを見た方が分かりやすいので、早速サンプルコードを見ていきましょう。
まずはリファクタリング前のコードです。
class Car def initialize(price) @price = price end def guarantee? false end end class ForeinCar < Car def guarantee? false end end class HighGradeCar < Car def guarantee? true end end
Car(車)クラス、Carクラスを継承した ForeinCar(外車)クラス・HighGradeCar(高級車)クラスがあります。
imported = false price = 200 car1 = if imported ForeinCar.new(price) elsif price > 100 HighGradeCar.new(price) else Car.new(price) end puts car1.guarantee? # -> true
作成するオブジェクトを決めるために条件分岐を使っています。また、複数箇所でオブジェクトを作成しており、同じ条件分岐が使われているとします。
このコードの問題点としては以下の点が挙げられます。
- 条件分岐のコードが重複していること
- 呼び出しているクラスと、オブジェクトが作られるクラス(ForeinCarなど)の結合度が強くなり、保守性が低くなっていること(例えば、ForeinCarクラスのクラス名や呼び出し方が変わると、呼び出し元のクラスも変更しなくてはいけなくなってしまいます)
リファクタリング後
「コンストラクタからファクトリメソッドへ」を使ってリファクタリングしていきます。
リファクタリングはシンプルで、先ほどの Carクラスに、オブジェクト作成のためのクラスメソッドを1つ追加するのみです。
class Car def self.create(imported, price) # ファクトリメソッド if imported ForeinCar.new(price) elsif price > 100 HighGradeCar.new(price) else new(price) end end end
create がファクトリメソッドです。
次のように実行すると結果はリファクタリング前と同じになります。
car2 = Car.create(imported, price)
puts car2.guarantee?
オブジェクトの作成は全てファクトリメソッドで行うようにすることで、コードの重複はなくなり、クラス間の結合度も弱くすることができました。
「コンストラクタからファクトリメソッドへ」という名前は、呼び出し元からコンストラクタを呼び出していた(newしていた)ものをファクトリメソッドを呼び出すように変える、という意味のようです。
おわりに
ここまでお読みいただきありがとうございます。
リファクタリング Rubyエディションでは、この記事とは別のサンプルコードで丁寧に説明されていて分かりやすかったので、ご興味ある方は是非ご覧ください。
- 作者:ジェイ・フィールズ,シェーン・ハービー,マーティン・ファウラー
- 発売日: 2020/03/21
- メディア: 単行本
次回はまた違うパターンをまとめていきます!
(追記)
第7弾として「サンドイッチメソッドの抽出」についてまとめました。
是非合わせてご覧ください。
ysk-pro.hatenablog.com